diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index a523baebba..d2ec2e2f6c 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -196,6 +196,10 @@ msgstr "" msgid "%q must be <= %d" msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "" + #: py/argcheck.c msgid "%q must be >= %d" msgstr "" @@ -1164,10 +1168,6 @@ msgstr "" msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "Initialization failed due to lack of memory" -msgstr "" - #: shared-bindings/bitops/__init__.c #, c-format msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" @@ -1802,11 +1802,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c -#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c -msgid "RAISE mode is not implemented" -msgstr "" - #: ports/raspberrypi/common-hal/countio/Counter.c msgid "RISE_AND_FALL not available on this chip" msgstr "" @@ -2308,20 +2303,10 @@ msgstr "" msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c #: ports/nrf/common-hal/watchdog/WatchDogTimer.c -#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: shared-bindings/watchdog/WatchDogTimer.c -msgid "WatchDogTimer is not currently running" -msgstr "" - -#: shared-bindings/watchdog/WatchDogTimer.c -msgid "WatchDogTimer.mode cannot be changed once set to WatchDogMode.RESET" -msgstr "" - #: py/builtinhelp.c #, c-format msgid "" @@ -4078,10 +4063,7 @@ msgstr "" msgid "syntax error in uctypes descriptor" msgstr "" -#: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c #: ports/nrf/common-hal/watchdog/WatchDogTimer.c -#: ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" msgstr "" @@ -4283,10 +4265,6 @@ msgstr "" msgid "value out of range of target" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "watchdog not initialized" -msgstr "" - #: shared-bindings/is31fl3741/FrameBuffer.c msgid "width must be greater than zero" msgstr "" diff --git a/main.c b/main.c index dff92da757..2607217e1b 100644 --- a/main.c +++ b/main.c @@ -241,6 +241,12 @@ void supervisor_execution_status(void) { } #endif +#if CIRCUITPY_WATCHDOG +pyexec_result_t *pyexec_result(void) { + return &_exec_result; +} +#endif + // Look for the first file that exists in the list of filenames, using mp_import_stat(). // Return its index. If no file found, return -1. STATIC const char *first_existing_file_in_list(const char *const *filenames, size_t n_filenames) { diff --git a/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c b/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c index 65d238ce75..435cfd6731 100644 --- a/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c +++ b/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c @@ -30,62 +30,71 @@ #include "shared-bindings/watchdog/__init__.h" #include "shared-bindings/watchdog/WatchDogTimer.h" +#include "shared-bindings/microcontroller/__init__.h" + #include "common-hal/watchdog/WatchDogTimer.h" #include "component/wdt.h" +#define SYNC_CTRL_WRITE while (WDT->SYNCBUSY.reg) {} + +static void watchdog_disable(void) { + // disable watchdog + WDT->CTRLA.reg = 0; + SYNC_CTRL_WRITE +} + +static void watchdog_enable(watchdog_watchdogtimer_obj_t *self) { + // disable watchdog for config + watchdog_disable(); + + int wdt_cycles = (int)(self->timeout * 1024); + if (wdt_cycles < 8) { + wdt_cycles = 8; + } + + // ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits) + int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1); + int setting = log2_wdt_cycles - 3; // CYC8_Val is 0 + + OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT) + + WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt + WDT->CONFIG.bit.PER = setting; // Set period for chip reset + WDT->CTRLA.bit.WEN = 0; // Disable window mode + SYNC_CTRL_WRITE + common_hal_watchdog_feed(self); // Clear watchdog interval + WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now! + SYNC_CTRL_WRITE +} + void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) { WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY; } void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { - if (self->mode == WATCHDOGMODE_RESET) { - mp_raise_RuntimeError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET")); - } else { - self->mode = WATCHDOGMODE_NONE; + if (self->mode == WATCHDOGMODE_NONE) { + return; } + watchdog_disable(); + self->mode = WATCHDOGMODE_NONE; } mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) { return self->timeout; } -STATIC void setup_wdt(watchdog_watchdogtimer_obj_t *self, int setting) { - OSC32KCTRL->OSCULP32K.bit.EN1K = 1; // Enable out 1K (for WDT) - - // disable watchdog for config - WDT->CTRLA.reg = 0; - while (WDT->SYNCBUSY.reg) { // Sync CTRL write - } - - WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt - WDT->CONFIG.bit.PER = setting; // Set period for chip reset - WDT->CTRLA.bit.WEN = 0; // Disable window mode - while (WDT->SYNCBUSY.reg) { // Sync CTRL write - } - common_hal_watchdog_feed(self); // Clear watchdog interval - WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now! - while (WDT->SYNCBUSY.reg) { - } -} - void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t new_timeout) { - int wdt_cycles = (int)(new_timeout * 1024); - if (wdt_cycles < 8) { - wdt_cycles = 8; + if (!(self->timeout < new_timeout || self->timeout > new_timeout)) { + return; } - if (wdt_cycles > 16384) { - mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value")); - } - // ceil(log2(n)) = 32 - __builtin_clz(n - 1) when n > 1 (if int is 32 bits) - int log2_wdt_cycles = (sizeof(int) * CHAR_BIT) - __builtin_clz(wdt_cycles - 1); - int setting = log2_wdt_cycles - 3; // CYC8_Val is 0 - float timeout = (8 << setting) / 1024.f; + + mp_arg_validate_int_max(new_timeout, 16, MP_QSTR_timeout); + self->timeout = new_timeout; if (self->mode == WATCHDOGMODE_RESET) { - setup_wdt(self, setting); + watchdog_enable(self); } - self->timeout = timeout; } watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self) { @@ -93,13 +102,23 @@ watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_ } void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) { - if (self->mode != new_mode) { - if (new_mode == WATCHDOGMODE_RAISE) { - mp_raise_NotImplementedError(translate("RAISE mode is not implemented")); - } else if (new_mode == WATCHDOGMODE_NONE) { - common_hal_watchdog_deinit(self); - } - self->mode = new_mode; - common_hal_watchdog_set_timeout(self, self->timeout); + if (self->mode == new_mode) { + return; } + + switch (new_mode) { + case WATCHDOGMODE_NONE: + common_hal_watchdog_deinit(self); + break; + case WATCHDOGMODE_RAISE: + mp_raise_NotImplementedError(NULL); + break; + case WATCHDOGMODE_RESET: + watchdog_enable(self); + break; + default: + return; + } + + self->mode = new_mode; } diff --git a/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h b/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h index ce34f0b8ab..ae214a95e6 100644 --- a/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h +++ b/ports/atmel-samd/common-hal/watchdog/WatchDogTimer.h @@ -28,6 +28,9 @@ #define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H #include "py/obj.h" + +#include "shared-module/watchdog/__init__.h" + #include "shared-bindings/watchdog/WatchDogMode.h" #include "shared-bindings/watchdog/WatchDogTimer.h" @@ -37,7 +40,4 @@ struct _watchdog_watchdogtimer_obj_t { watchdog_watchdogmode_t mode; }; -// This needs to be called in order to disable the watchdog -// void watchdog_reset(void); - #endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 8ae2d3740e..4693311d1a 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -388,13 +388,16 @@ void reset_port(void) { #if CIRCUITPY_BUSIO reset_sercoms(); #endif + #if CIRCUITPY_AUDIOIO audio_dma_reset(); audioout_reset(); #endif + #if CIRCUITPY_AUDIOBUSIO pdmin_reset(); #endif + #if CIRCUITPY_AUDIOBUSIO_I2SOUT i2sout_reset(); #endif @@ -406,14 +409,18 @@ void reset_port(void) { #if CIRCUITPY_TOUCHIO && CIRCUITPY_TOUCHIO_USE_NATIVE touchin_reset(); #endif + eic_reset(); + #if CIRCUITPY_PULSEIO pulsein_reset(); pulseout_reset(); #endif + #if CIRCUITPY_PWMIO pwmout_reset(); #endif + #if CIRCUITPY_PWMIO || CIRCUITPY_AUDIOIO || CIRCUITPY_FREQUENCYIO reset_timers(); #endif @@ -423,6 +430,10 @@ void reset_port(void) { analogout_reset(); #endif + #if CIRCUITPY_WATCHDOG + watchdog_reset(); + #endif + reset_gclks(); #if CIRCUITPY_PEW diff --git a/ports/espressif/common-hal/watchdog/WatchDogTimer.c b/ports/espressif/common-hal/watchdog/WatchDogTimer.c index 78c04ba533..68437958e5 100644 --- a/ports/espressif/common-hal/watchdog/WatchDogTimer.c +++ b/ports/espressif/common-hal/watchdog/WatchDogTimer.c @@ -25,17 +25,27 @@ */ #include "py/runtime.h" -#include "common-hal/watchdog/WatchDogTimer.h" #include "shared-bindings/watchdog/__init__.h" #include "shared-bindings/microcontroller/__init__.h" +#include "common-hal/watchdog/WatchDogTimer.h" + #include "esp_task_wdt.h" extern void esp_task_wdt_isr_user_handler(void); + void esp_task_wdt_isr_user_handler(void) { + // just delete, deiniting TWDT in isr context causes a crash + if (esp_task_wdt_delete(NULL) == ESP_OK) { + watchdog_watchdogtimer_obj_t *self = &common_hal_mcu_watchdogtimer_obj; + self->mode = WATCHDOGMODE_NONE; + } + + // schedule watchdog timeout exception mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&mp_watchdog_timeout_exception)); MP_STATE_THREAD(mp_pending_exception) = &mp_watchdog_timeout_exception; + #if MICROPY_ENABLE_SCHEDULER if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; @@ -44,31 +54,28 @@ void esp_task_wdt_isr_user_handler(void) { } void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) { - if (esp_task_wdt_reset() != ESP_OK) { - mp_raise_RuntimeError(translate("watchdog not initialized")); - } + esp_task_wdt_reset(); } void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { + if (self->mode == WATCHDOGMODE_NONE) { + return; + } if (esp_task_wdt_delete(NULL) == ESP_OK && esp_task_wdt_deinit() == ESP_OK) { self->mode = WATCHDOGMODE_NONE; } } -void watchdog_reset(void) { - common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj); -} - -static void wdt_config(watchdog_watchdogtimer_obj_t *self) { +static void wdt_config(uint32_t timeout, watchdog_watchdogmode_t mode) { // enable panic hanler in WATCHDOGMODE_RESET mode // initialize Task Watchdog Timer (TWDT) esp_task_wdt_config_t twdt_config = { - .timeout_ms = (uint32_t)self->timeout, + .timeout_ms = timeout, .idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores - .trigger_panic = (self->mode == WATCHDOGMODE_RESET), + .trigger_panic = (mode == WATCHDOGMODE_RESET), }; if (esp_task_wdt_init(&twdt_config) != ESP_OK) { - mp_raise_RuntimeError(translate("Initialization failed due to lack of memory")); + mp_raise_msg(&mp_type_MemoryError, NULL); } esp_task_wdt_add(NULL); } @@ -78,12 +85,17 @@ mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) { } void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t new_timeout) { - if ((uint64_t)new_timeout > UINT32_MAX) { - mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value")); + if (!(self->timeout < new_timeout || self->timeout > new_timeout)) { + return; } - if ((uint32_t)self->timeout != (uint32_t)new_timeout) { - self->timeout = new_timeout; - wdt_config(self); + + if ((uint64_t)new_timeout > UINT32_MAX) { + mp_raise_ValueError_varg(translate("%q must be <= %u"), MP_QSTR_timeout, UINT32_MAX); + } + self->timeout = new_timeout; + + if (self->mode != WATCHDOGMODE_NONE) { + wdt_config(new_timeout, self->mode); } } @@ -92,8 +104,21 @@ watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_ } void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) { - if (self->mode != new_mode) { - self->mode = new_mode; - wdt_config(self); + if (self->mode == new_mode) { + return; } + + switch (new_mode) { + case WATCHDOGMODE_NONE: + common_hal_watchdog_deinit(self); + break; + case WATCHDOGMODE_RAISE: + case WATCHDOGMODE_RESET: + wdt_config(self->timeout, new_mode); + break; + default: + return; + } + + self->mode = new_mode; } diff --git a/ports/espressif/common-hal/watchdog/WatchDogTimer.h b/ports/espressif/common-hal/watchdog/WatchDogTimer.h index 8d95bfa4cc..461d11f18c 100644 --- a/ports/espressif/common-hal/watchdog/WatchDogTimer.h +++ b/ports/espressif/common-hal/watchdog/WatchDogTimer.h @@ -28,6 +28,9 @@ #define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H #include "py/obj.h" + +#include "shared-module/watchdog/__init__.h" + #include "shared-bindings/watchdog/WatchDogMode.h" #include "shared-bindings/watchdog/WatchDogTimer.h" @@ -37,7 +40,4 @@ struct _watchdog_watchdogtimer_obj_t { watchdog_watchdogmode_t mode; }; -// This needs to be called in order to disable the watchdog -void watchdog_reset(void); - #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H diff --git a/ports/nrf/common-hal/watchdog/WatchDogTimer.c b/ports/nrf/common-hal/watchdog/WatchDogTimer.c index 99c360c46d..1ac0ee1076 100644 --- a/ports/nrf/common-hal/watchdog/WatchDogTimer.c +++ b/ports/nrf/common-hal/watchdog/WatchDogTimer.c @@ -33,12 +33,12 @@ #include "py/objproperty.h" #include "py/runtime.h" -#include "common-hal/watchdog/WatchDogTimer.h" - #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/watchdog/__init__.h" #include "shared-bindings/watchdog/WatchDogTimer.h" +#include "common-hal/watchdog/WatchDogTimer.h" + #include "supervisor/port.h" #include "nrf/timers.h" @@ -107,10 +107,6 @@ void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { self->mode = WATCHDOGMODE_NONE; } -void watchdog_reset(void) { - common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj); -} - mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) { return self->timeout; } diff --git a/ports/nrf/common-hal/watchdog/WatchDogTimer.h b/ports/nrf/common-hal/watchdog/WatchDogTimer.h index 1ff654c321..e298a71ba7 100644 --- a/ports/nrf/common-hal/watchdog/WatchDogTimer.h +++ b/ports/nrf/common-hal/watchdog/WatchDogTimer.h @@ -28,6 +28,9 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H #include "py/obj.h" + +#include "shared-module/watchdog/__init__.h" + #include "shared-bindings/watchdog/WatchDogMode.h" #include "shared-bindings/watchdog/WatchDogTimer.h" @@ -37,8 +40,4 @@ struct _watchdog_watchdogtimer_obj_t { watchdog_watchdogmode_t mode; }; -// This needs to be called in order to disable the watchdog if it's set to -// "RAISE". If set to "RESET", then the watchdog cannot be reset. -void watchdog_reset(void); - #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H diff --git a/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c b/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c index f23ccda777..61c71ccd62 100644 --- a/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c +++ b/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.c @@ -25,45 +25,43 @@ */ #include "py/runtime.h" -#include "common-hal/watchdog/WatchDogTimer.h" #include "shared-bindings/watchdog/__init__.h" #include "shared-bindings/microcontroller/__init__.h" -#include "src/rp2_common/hardware_watchdog/include/hardware/watchdog.h" +#include "common-hal/watchdog/WatchDogTimer.h" + +#include "hardware/watchdog.h" + +#define WATCHDOG_ENABLE watchdog_enable(self->timeout * 1000, false) void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self) { watchdog_update(); } void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { - if (self->mode == WATCHDOGMODE_RESET) { - mp_raise_RuntimeError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET")); - } else { - self->mode = WATCHDOGMODE_NONE; + if (self->mode == WATCHDOGMODE_NONE) { + return; } + hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS); + self->mode = WATCHDOGMODE_NONE; } -/* -void watchdog_reset(void) { - common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj); -} -*/ - mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) { return self->timeout; } void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t new_timeout) { - // max timeout is 8.388607 sec - // this is rounded down to 8.388 sec - uint64_t timeout = new_timeout * 1000; - if (timeout > 8388) { - mp_raise_ValueError(translate("timeout duration exceeded the maximum supported value")); + if (!(self->timeout < new_timeout || self->timeout > new_timeout)) { + return; } - if ((uint16_t)self->timeout != timeout) { - watchdog_enable(timeout, false); - self->timeout = new_timeout; + + // max timeout is 8.388607 sec, this is rounded down to 8 sec + mp_arg_validate_int_max(new_timeout, 8, MP_QSTR_timeout); + self->timeout = new_timeout; + + if (self->mode == WATCHDOGMODE_RESET) { + WATCHDOG_ENABLE; } } @@ -72,12 +70,23 @@ watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_ } void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t new_mode) { - if (self->mode != new_mode) { - if (new_mode == WATCHDOGMODE_RAISE) { - mp_raise_NotImplementedError(translate("RAISE mode is not implemented")); - } else if (new_mode == WATCHDOGMODE_NONE) { - common_hal_watchdog_deinit(self); - } - self->mode = new_mode; + if (self->mode == new_mode) { + return; } + + switch (new_mode) { + case WATCHDOGMODE_NONE: + common_hal_watchdog_deinit(self); + break; + case WATCHDOGMODE_RAISE: + mp_raise_NotImplementedError(NULL); + break; + case WATCHDOGMODE_RESET: + WATCHDOG_ENABLE; + break; + default: + return; + } + + self->mode = new_mode; } diff --git a/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.h b/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.h index ce34f0b8ab..ae214a95e6 100644 --- a/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.h +++ b/ports/raspberrypi/common-hal/watchdog/WatchDogTimer.h @@ -28,6 +28,9 @@ #define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H #include "py/obj.h" + +#include "shared-module/watchdog/__init__.h" + #include "shared-bindings/watchdog/WatchDogMode.h" #include "shared-bindings/watchdog/WatchDogTimer.h" @@ -37,7 +40,4 @@ struct _watchdog_watchdogtimer_obj_t { watchdog_watchdogmode_t mode; }; -// This needs to be called in order to disable the watchdog -// void watchdog_reset(void); - #endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 5f18a4d2ed..a872c7b463 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -207,6 +207,10 @@ void reset_port(void) { ssl_reset(); #endif + #if CIRCUITPY_WATCHDOG + watchdog_reset(); + #endif + #if CIRCUITPY_WIFI wifi_reset(); #endif diff --git a/ports/silabs/common-hal/watchdog/WatchDogTimer.c b/ports/silabs/common-hal/watchdog/WatchDogTimer.c index b6158e1cc6..d65c794833 100644 --- a/ports/silabs/common-hal/watchdog/WatchDogTimer.c +++ b/ports/silabs/common-hal/watchdog/WatchDogTimer.c @@ -41,10 +41,6 @@ void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self) { WDOG_Enable(false); } -void watchdog_reset(void) { - common_hal_watchdog_deinit(&common_hal_mcu_watchdogtimer_obj); -} - mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self) { return self->timeout; } diff --git a/ports/silabs/common-hal/watchdog/WatchDogTimer.h b/ports/silabs/common-hal/watchdog/WatchDogTimer.h index d1538bd491..9aad655e73 100644 --- a/ports/silabs/common-hal/watchdog/WatchDogTimer.h +++ b/ports/silabs/common-hal/watchdog/WatchDogTimer.h @@ -28,6 +28,9 @@ #define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H #include "py/obj.h" + +#include "shared-module/watchdog/__init__.h" + #include "shared-bindings/watchdog/WatchDogMode.h" #include "shared-bindings/watchdog/WatchDogTimer.h" @@ -37,7 +40,4 @@ struct _watchdog_watchdogtimer_obj_t { watchdog_watchdogmode_t mode; }; -// This needs to be called in order to disable the watchdog -void watchdog_reset(void); - #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WATCHDOG_WATCHDOGTIMER_H diff --git a/ports/silabs/supervisor/port.c b/ports/silabs/supervisor/port.c index 8247c813a7..fba90882df 100644 --- a/ports/silabs/supervisor/port.c +++ b/ports/silabs/supervisor/port.c @@ -192,6 +192,10 @@ void reset_port(void) { #if CIRCUITPY_RTC rtc_reset(); #endif + + #if CIRCUITPY_WATCHDOG + watchdog_reset(); + #endif } void reset_to_bootloader(void) { diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index c819d46db8..3974e27df4 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -666,6 +666,7 @@ SRC_SHARED_MODULE_ALL = \ usb/core/__init__.c \ usb/core/Device.c \ ustack/__init__.c \ + watchdog/__init__.c \ zlib/__init__.c \ vectorio/Circle.c \ vectorio/Polygon.c \ diff --git a/shared-bindings/watchdog/WatchDogMode.c b/shared-bindings/watchdog/WatchDogMode.c index c707054d27..944ab451fa 100644 --- a/shared-bindings/watchdog/WatchDogMode.c +++ b/shared-bindings/watchdog/WatchDogMode.c @@ -1,9 +1,9 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2020 Sean Cross for Adafruit Industries + * Copyright (c) 2023 MicroDev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,76 +24,28 @@ * THE SOFTWARE. */ +#include "py/enum.h" + #include "shared-bindings/watchdog/WatchDogMode.h" +MAKE_ENUM_VALUE(watchdog_watchdogmode_type, watchdogmode, RAISE, WATCHDOGMODE_RAISE); +MAKE_ENUM_VALUE(watchdog_watchdogmode_type, watchdogmode, RESET, WATCHDOGMODE_RESET); + //| class WatchDogMode: -//| """run state of the watchdog timer""" +//| """Run state of the watchdog timer.""" //| -//| def __init__(self) -> None: -//| """Enum-like class to define the run mode of the watchdog timer.""" //| RAISE: WatchDogMode -//| """Raise an exception when the WatchDogTimer expires. -//| -//| **Limitations:** ``RAISE`` mode is not supported on SAMD or RP2040. -//| -//| :type WatchDogMode:""" +//| """Raise an exception when the `WatchDogTimer` expires.""" //| //| RESET: WatchDogMode -//| """Reset the system if the WatchDogTimer expires. +//| """Reset the system when the `WatchDogTimer` expires.""" //| -//| :type WatchDogMode:""" -//| -const mp_obj_type_t watchdog_watchdogmode_type; - -const watchdog_watchdogmode_obj_t watchdog_watchdogmode_raise_obj = { - { &watchdog_watchdogmode_type }, +MAKE_ENUM_MAP(watchdog_watchdogmode) { + MAKE_ENUM_MAP_ENTRY(watchdogmode, RAISE), + MAKE_ENUM_MAP_ENTRY(watchdogmode, RESET), }; +STATIC MP_DEFINE_CONST_DICT(watchdog_watchdogmode_locals_dict, watchdog_watchdogmode_locals_table); -const watchdog_watchdogmode_obj_t watchdog_watchdogmode_reset_obj = { - { &watchdog_watchdogmode_type }, -}; +MAKE_PRINTER(watchdog, watchdog_watchdogmode); -watchdog_watchdogmode_t watchdog_watchdogmode_obj_to_type(mp_obj_t obj) { - if (obj == MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)) { - return WATCHDOGMODE_RAISE; - } else if (obj == MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)) { - return WATCHDOGMODE_RESET; - } - return WATCHDOGMODE_NONE; -} - -mp_obj_t watchdog_watchdogmode_type_to_obj(watchdog_watchdogmode_t mode) { - switch (mode) { - case WATCHDOGMODE_RAISE: - return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_raise_obj); - case WATCHDOGMODE_RESET: - return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_reset_obj); - case WATCHDOGMODE_NONE: - default: - return MP_ROM_NONE; - } -} - -STATIC const mp_rom_map_elem_t watchdog_watchdogmode_locals_dict_table[] = { - {MP_ROM_QSTR(MP_QSTR_RAISE), MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)}, - {MP_ROM_QSTR(MP_QSTR_RESET), MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(watchdog_watchdogmode_locals_dict, watchdog_watchdogmode_locals_dict_table); - -STATIC void watchdog_watchdogmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - qstr runmode = MP_QSTR_None; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)) { - runmode = MP_QSTR_RAISE; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)) { - runmode = MP_QSTR_RESET; - } - mp_printf(print, "%q.%q.%q", MP_QSTR_watchdog, MP_QSTR_WatchDogMode, - runmode); -} - -const mp_obj_type_t watchdog_watchdogmode_type = { - { &mp_type_type }, - .name = MP_QSTR_WatchDogMode, - .print = watchdog_watchdogmode_print, - .locals_dict = (mp_obj_t)&watchdog_watchdogmode_locals_dict, -}; +MAKE_ENUM_TYPE(watchdog, WatchDogMode, watchdog_watchdogmode); diff --git a/shared-bindings/watchdog/WatchDogMode.h b/shared-bindings/watchdog/WatchDogMode.h index fb09445a9f..fd27d4d46a 100644 --- a/shared-bindings/watchdog/WatchDogMode.h +++ b/shared-bindings/watchdog/WatchDogMode.h @@ -1,5 +1,5 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * @@ -27,7 +27,7 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H -#include "py/obj.h" +#include "py/enum.h" typedef enum { WATCHDOGMODE_NONE, @@ -37,13 +37,4 @@ typedef enum { extern const mp_obj_type_t watchdog_watchdogmode_type; -watchdog_watchdogmode_t watchdog_watchdogmode_obj_to_type(mp_obj_t obj); -mp_obj_t watchdog_watchdogmode_type_to_obj(watchdog_watchdogmode_t mode); - -typedef struct { - mp_obj_base_t base; -} watchdog_watchdogmode_obj_t; -extern const watchdog_watchdogmode_obj_t watchdog_watchdogmode_raise_obj; -extern const watchdog_watchdogmode_obj_t watchdog_watchdogmode_reset_obj; - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H diff --git a/shared-bindings/watchdog/WatchDogTimer.c b/shared-bindings/watchdog/WatchDogTimer.c index acfd353c34..49cfdaecb4 100644 --- a/shared-bindings/watchdog/WatchDogTimer.c +++ b/shared-bindings/watchdog/WatchDogTimer.c @@ -50,29 +50,31 @@ //| //| def __init__(self) -> None: -//| """Not currently dynamically supported. Access the sole instance through `microcontroller.watchdog`.""" +//| """Access the sole instance through `microcontroller.watchdog`.""" //| ... //| def feed(self) -> None: //| """Feed the watchdog timer. This must be called regularly, otherwise -//| the timer will expire.""" +//| the timer will expire. Silently does nothing if the watchdog isn't active.""" //| ... STATIC mp_obj_t watchdog_watchdogtimer_feed(mp_obj_t self_in) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); - watchdog_watchdogmode_t current_mode = common_hal_watchdog_get_mode(self); - - if (current_mode == WATCHDOGMODE_NONE) { - mp_raise_ValueError(translate("WatchDogTimer is not currently running")); + if (common_hal_watchdog_get_mode(self) != WATCHDOGMODE_NONE) { + common_hal_watchdog_feed(self); } - - common_hal_watchdog_feed(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_feed_obj, watchdog_watchdogtimer_feed); //| def deinit(self) -> None: -//| """Stop the watchdog timer. This may raise an error if the watchdog -//| timer cannot be disabled on this platform.""" +//| """Stop the watchdog timer. +//| +//| :raises RuntimeError: if the watchdog timer cannot be disabled on this platform. +//| +//| .. note:: This is deprecated in ``9.0.0`` and will be removed in ``10.0.0``. +//| Set watchdog `mode` to `None` instead. +//| +//| """ //| ... STATIC mp_obj_t watchdog_watchdogtimer_deinit(mp_obj_t self_in) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -83,7 +85,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_deinit_obj, watchdog_wat //| timeout: float //| """The maximum number of seconds that can elapse between calls -//| to feed()""" +//| to `feed()`""" STATIC mp_obj_t watchdog_watchdogtimer_obj_get_timeout(mp_obj_t self_in) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_float(common_hal_watchdog_get_timeout(self)); @@ -94,7 +96,7 @@ STATIC mp_obj_t watchdog_watchdogtimer_obj_set_timeout(mp_obj_t self_in, mp_obj_ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_float_t timeout = mp_obj_get_float(timeout_obj); - mp_arg_validate_int_min((int)timeout, 0, MP_QSTR_timeout); + mp_arg_validate_int_min(timeout, 0, MP_QSTR_timeout); common_hal_watchdog_set_timeout(self, timeout); return mp_const_none; @@ -105,44 +107,31 @@ MP_PROPERTY_GETSET(watchdog_watchdogtimer_timeout_obj, (mp_obj_t)&watchdog_watchdogtimer_get_timeout_obj, (mp_obj_t)&watchdog_watchdogtimer_set_timeout_obj); -//| mode: WatchDogMode -//| """The current operating mode of the WatchDogTimer `watchdog.WatchDogMode`. +//| mode: Optional[WatchDogMode] +//| """The current operating mode of the WatchDogTimer `watchdog.WatchDogMode` or `None` when +//| the timer is disabled. //| -//| Setting a WatchDogMode activates the WatchDog:: +//| Setting a `WatchDogMode` activates the WatchDog:: //| -//| import microcontroller -//| import watchdog +//| from microcontroller import watchdog +//| from watchdog import WatchDogMode //| -//| w = microcontroller.watchdog -//| w.timeout = 5 -//| w.mode = watchdog.WatchDogMode.RAISE +//| watchdog.timeout = 5 +//| watchdog.mode = WatchDogMode.RESET //| //| -//| Once set, the WatchDogTimer will perform the specified action if the timer expires.""" +//| Once set, the `WatchDogTimer` will perform the specified action if the timer expires.""" //| STATIC mp_obj_t watchdog_watchdogtimer_obj_get_mode(mp_obj_t self_in) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); - return watchdog_watchdogmode_type_to_obj(common_hal_watchdog_get_mode(self)); + return cp_enum_find(&watchdog_watchdogmode_type, common_hal_watchdog_get_mode(self)); } MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_mode_obj, watchdog_watchdogtimer_obj_get_mode); -STATIC mp_obj_t watchdog_watchdogtimer_obj_set_mode(mp_obj_t self_in, mp_obj_t mode_obj) { +STATIC mp_obj_t watchdog_watchdogtimer_obj_set_mode(mp_obj_t self_in, mp_obj_t obj) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); - watchdog_watchdogmode_t current_mode = common_hal_watchdog_get_mode(self); - watchdog_watchdogmode_t new_mode = watchdog_watchdogmode_obj_to_type(mode_obj); - mp_float_t current_timeout = common_hal_watchdog_get_timeout(self); - - // When setting the mode, the timeout value must be greater than zero - if (new_mode == WATCHDOGMODE_RESET || new_mode == WATCHDOGMODE_RAISE) { - mp_arg_validate_int_min((int)current_timeout, 0, MP_QSTR_timeout); - } - - // Don't allow changing the mode once the watchdog timer has been started - if (current_mode == WATCHDOGMODE_RESET && new_mode != WATCHDOGMODE_RESET) { - mp_raise_TypeError(translate("WatchDogTimer.mode cannot be changed once set to WatchDogMode.RESET")); - } - - common_hal_watchdog_set_mode(self, new_mode); + watchdog_watchdogmode_t mode = (obj == mp_const_none) ? WATCHDOGMODE_NONE : cp_enum_value(&watchdog_watchdogmode_type, obj, MP_QSTR_mode); + common_hal_watchdog_set_mode(self, mode); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(watchdog_watchdogtimer_set_mode_obj, watchdog_watchdogtimer_obj_set_mode); diff --git a/shared-bindings/watchdog/WatchDogTimer.h b/shared-bindings/watchdog/WatchDogTimer.h index 48044748a9..a566b267d6 100644 --- a/shared-bindings/watchdog/WatchDogTimer.h +++ b/shared-bindings/watchdog/WatchDogTimer.h @@ -27,14 +27,14 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGTIMER_H #define MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGTIMER_H -#include +#include "py/obj.h" #include "shared-bindings/watchdog/WatchDogMode.h" typedef struct _watchdog_watchdogtimer_obj_t watchdog_watchdogtimer_obj_t; extern void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self); -extern void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t); +extern void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t mode); extern watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self); extern void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t timeout); diff --git a/shared-module/watchdog/__init__.c b/shared-module/watchdog/__init__.c new file mode 100644 index 0000000000..b348647c06 --- /dev/null +++ b/shared-module/watchdog/__init__.c @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "shared/runtime/pyexec.h" + +#include "shared-module/watchdog/__init__.h" + +#include "shared-bindings/watchdog/WatchDogTimer.h" +#include "shared-bindings/microcontroller/__init__.h" + +void watchdog_reset(void) { + watchdog_watchdogtimer_obj_t *self = &common_hal_mcu_watchdogtimer_obj; + if (self->mode == WATCHDOGMODE_RESET) { + mp_obj_t exception = pyexec_result()->exception; + if (exception != MP_OBJ_NULL && + exception != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)) && + exception != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { + return; + } + } + common_hal_watchdog_deinit(self); +} diff --git a/shared-module/watchdog/__init__.h b/shared-module/watchdog/__init__.h new file mode 100644 index 0000000000..219ccfc7b4 --- /dev/null +++ b/shared-module/watchdog/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_WATCHDOG___INIT___H +#define MICROPY_INCLUDED_SHARED_MODULE_WATCHDOG___INIT___H + +extern void watchdog_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_WATCHDOG___INIT___H diff --git a/shared/runtime/pyexec.h b/shared/runtime/pyexec.h index 411426eaaa..d0c012fe46 100644 --- a/shared/runtime/pyexec.h +++ b/shared/runtime/pyexec.h @@ -67,6 +67,10 @@ extern uint8_t pyexec_repl_active; int pyexec_exit_handler(const void *source, pyexec_result_t *result); #endif +#if CIRCUITPY_WATCHDOG +pyexec_result_t *pyexec_result(void); +#endif + #if MICROPY_REPL_INFO mp_obj_t pyb_set_repl_info(mp_obj_t o_value); MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);