Implement safemode.py

This commit is contained in:
Dan Halbert 2023-02-11 23:50:20 -05:00
parent 795e46cedd
commit d8231f1588
54 changed files with 497 additions and 341 deletions

View File

@ -138,6 +138,14 @@ Behavior
- Adds a safe mode that does not run user code after a hard crash or brown out. This makes it
possible to fix code that causes nasty crashes by making it available through mass storage after
the crash. A reset (the button) is needed after it's fixed to get back into normal mode.
- Safe mode may be handled programmatically by providing a ``safemode.py``.
``safemode.py`` is run if the board has reset due to entering safe mode. USB is not
available so nothing can be printed. ``safemode.py`` can determine why the safe mode occurred
using ``supervisor.runtime.safe_mode_reason``, and take appropriate action. For instance,
if a hard crash occurred, ``safemode.py`` may do a ``microcontroller.reset()``
to automatically restart despite the crash.
If the battery is low, but is being charged, ``safemode.py`` may put the board in deep sleep
for a while. Or it may simply reset, and have ``code.py`` check the voltage and do the sleep.
- RGB status LED indicating CircuitPython state.
- One green flash - code completed without error.
- Two red flashes - code ended due to an exception.
@ -145,9 +153,9 @@ Behavior
- Re-runs ``code.py`` or other main file after file system writes by a workflow. (Disable with
``supervisor.disable_autoreload()``)
- Autoreload is disabled while the REPL is active.
- Main is one of these: ``code.txt``, ``code.py``, ``main.py``,
``main.txt``
- Boot is one of these: ``boot.py``, ``boot.txt``
- ``code.py`` may also be named``code.txt``, ``main.py``, or ``main.txt``.
- ``boot.py`` may also be named ``boot.txt``.
- ``safemode.py`` may also be named ``safemode.txt``.
API
~~~

View File

@ -35,6 +35,12 @@ msgid ""
"https://github.com/adafruit/circuitpython/issues\n"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid ""
"\n"
"To exit, reset the board without requesting safe mode."
msgstr ""
#: py/obj.c
msgid " File \"%q\""
msgstr ""
@ -85,7 +91,7 @@ msgstr ""
#: ports/raspberrypi/common-hal/alarm/__init__.c
#: ports/raspberrypi/common-hal/analogio/AnalogOut.c
#: ports/raspberrypi/common-hal/rtc/RTC.c ports/stm/common-hal/alarm/__init__.c
#: ports/stm/common-hal/rtc/RTC.c
#: ports/stm/common-hal/canio/Listener.c ports/stm/common-hal/rtc/RTC.c
msgid "%q"
msgstr ""
@ -589,13 +595,6 @@ msgstr ""
msgid "Both RX and TX required for flow control"
msgstr ""
#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h
#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h
msgid "Both buttons were pressed at start up.\n"
msgstr ""
#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
msgid "Both pins must support hardware interrupts"
msgstr ""
@ -661,12 +660,6 @@ msgstr ""
msgid "Bus pin %d is already in use"
msgstr ""
#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h
#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h
#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h
msgid "Button A was pressed at start up.\n"
msgstr ""
#: shared-bindings/_bleio/UUID.c
msgid "Byte buffer must be 16 bytes."
msgstr ""
@ -934,6 +927,10 @@ msgstr ""
msgid "Error in regex"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Error in safemode.py."
msgstr ""
#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c
msgid "Error: Failure to bind"
msgstr ""
@ -1006,10 +1003,6 @@ msgstr ""
msgid "Failed to write internal flash."
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Fatal error."
msgstr ""
#: py/moduerrno.c
msgid "File exists"
msgstr ""
@ -1209,6 +1202,10 @@ msgstr ""
msgid "Internal watchdog timer expired."
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Interrupt error."
msgstr ""
#: py/argcheck.c shared-bindings/digitalio/DigitalInOut.c
msgid "Invalid %q"
msgstr ""
@ -1257,10 +1254,6 @@ msgstr ""
msgid "Invalid format chunk size"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Invalid memory access."
msgstr ""
#: ports/espressif/common-hal/wifi/Radio.c
msgid "Invalid multicast MAC address"
msgstr ""
@ -1549,10 +1542,6 @@ msgstr ""
msgid "No timer available"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Nordic system firmware failure assertion."
msgstr ""
#: ports/nrf/common-hal/_bleio/__init__.c
msgid "Nordic system firmware out of memory"
msgstr ""
@ -2003,24 +1992,12 @@ msgstr ""
msgid "Temperature read timed out"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "The BOOT button was pressed at start up.\n"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid ""
"The CircuitPython heap was corrupted because the stack was too small.\n"
"Increase the stack size if you know how. If not:"
msgstr ""
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
msgid "The SW38 button was pressed at start up.\n"
msgstr ""
#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h
msgid "The VOLUME button was pressed at start up.\n"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid ""
"The `microcontroller` module was used to boot into safe mode. Press reset to "
@ -2031,17 +2008,6 @@ msgstr ""
msgid "The above exception was the direct cause of the following exception:"
msgstr ""
#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h
msgid "The central button was pressed at start up.\n"
msgstr ""
#: ports/nrf/boards/aramcon2_badge/mpconfigboard.h
msgid "The left button was pressed at start up.\n"
msgstr ""
#: shared-bindings/rgbmatrix/RGBMatrix.c
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
msgstr ""
@ -2069,6 +2035,10 @@ msgstr ""
msgid "The sample's signedness does not match the mixer's"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "Third-party firmware fatal error."
msgstr ""
#: shared-module/imagecapture/ParallelImageCapture.c
msgid "This microcontroller does not support continuous capture."
msgstr ""
@ -2101,10 +2071,6 @@ msgstr ""
msgid "Timeout is too long: Maximum timeout length is %d seconds"
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "To exit, please reset the board without requesting safe mode."
msgstr ""
#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c
msgid "Too many channels in sample"
msgstr ""
@ -2405,9 +2371,44 @@ msgstr ""
msgid "You are in safe mode because:\n"
msgstr ""
#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h
#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h
msgid "You pressed both buttons at start up."
msgstr ""
#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h
#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h
#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h
msgid "You pressed button A at start up."
msgstr ""
#: supervisor/shared/safe_mode.c
msgid ""
"You pressed the reset button during boot. Press again to exit safe mode."
msgid "You pressed the BOOT button at start up."
msgstr ""
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
msgid "You pressed the SW38 button at start up."
msgstr ""
#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h
msgid "You pressed the VOLUME button at start up."
msgstr ""
#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h
#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h
msgid "You pressed the central button at start up."
msgstr ""
#: ports/nrf/boards/aramcon2_badge/mpconfigboard.h
msgid "You pressed the left button at start up."
msgstr ""
#: supervisor/shared/safe_mode.c
msgid "You pressed the reset button during boot."
msgstr ""
#: py/objtype.c

65
main.c
View File

@ -358,7 +358,7 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
} else {
serial_write_compressed(translate("Auto-reload is off.\n"));
}
if (safe_mode != NO_SAFE_MODE) {
if (safe_mode != SAFE_MODE_NONE) {
serial_write_compressed(translate("Running in safe mode! Not running saved code.\n"));
}
}
@ -384,11 +384,11 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
// Do the filesystem flush check before reload in case another write comes
// in while we're doing the flush.
if (safe_mode == NO_SAFE_MODE) {
if (safe_mode == SAFE_MODE_NONE) {
stack_resize();
filesystem_flush();
}
if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) {
if (safe_mode == SAFE_MODE_NONE && !autoreload_pending()) {
static const char *const supported_filenames[] = {
"code.txt", "code.py", "main.py", "main.txt"
};
@ -510,7 +510,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
} else
#endif
if (_exec_result.return_code != PYEXEC_EXCEPTION) {
if (safe_mode == NO_SAFE_MODE) {
if (safe_mode == SAFE_MODE_NONE) {
color = ALL_DONE;
blink_count = ALL_DONE_BLINKS;
} else {
@ -730,8 +730,32 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
vstr_t *boot_output;
#if CIRCUITPY_SAFEMODE_PY
STATIC void __attribute__ ((noinline)) run_safemode_py(safe_mode_t safe_mode) {
// Don't run if we aren't in safe mode or we won't be able to find safemode.py.
if (safe_mode == SAFE_MODE_NONE || !filesystem_present()) {
return;
}
supervisor_allocation *heap = allocate_remaining_memory();
start_mp(heap);
static const char *const safemode_py_filenames[] = {"safemode.py", "safemode.txt"};
maybe_run_list(safemode_py_filenames, MP_ARRAY_SIZE(safemode_py_filenames));
// If safemode.py itself caused an error, change the safe_mode state to indicate that.
if (_exec_result.exception != MP_OBJ_NULL &&
_exec_result.exception != MP_OBJ_SENTINEL) {
set_safe_mode(SAFE_MODE_SAFEMODE_PY_ERROR);
}
cleanup_after_vm(heap, _exec_result.exception);
_exec_result.exception = NULL;
}
#endif
STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
if (safe_mode == NO_HEAP) {
if (safe_mode == SAFE_MODE_NO_HEAP) {
return;
}
@ -739,7 +763,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
// There is USB setup to do even if boot.py is not actually run.
const bool ok_to_run = filesystem_present()
&& safe_mode == NO_SAFE_MODE
&& safe_mode == SAFE_MODE_NONE
&& MP_STATE_VM(vfs_mount_table) != NULL;
static const char *const boot_py_filenames[] = {"boot.py", "boot.txt"};
@ -913,7 +937,7 @@ STATIC int run_repl(void) {
int __attribute__((used)) main(void) {
// initialise the cpu and peripherals
safe_mode_t safe_mode = port_init();
set_safe_mode(port_init());
// Turn on RX and TX LEDs if we have them.
init_rxtx_leds();
@ -926,8 +950,8 @@ int __attribute__((used)) main(void) {
#endif
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
if (safe_mode == NO_SAFE_MODE) {
safe_mode = wait_for_safe_mode_reset();
if (get_safe_mode() == SAFE_MODE_NONE) {
set_safe_mode(wait_for_safe_mode_reset());
}
stack_init();
@ -956,8 +980,8 @@ int __attribute__((used)) main(void) {
// Check whether CIRCUITPY is available. No need to reset to get safe mode
// since we haven't run user code yet.
if (!filesystem_init(safe_mode == NO_SAFE_MODE, false)) {
safe_mode = NO_CIRCUITPY;
if (!filesystem_init(get_safe_mode() == SAFE_MODE_NONE, false)) {
set_safe_mode(SAFE_MODE_NO_CIRCUITPY);
}
#if CIRCUITPY_ALARM
@ -982,16 +1006,23 @@ int __attribute__((used)) main(void) {
supervisor_set_run_reason(RUN_REASON_STARTUP);
// If not in safe mode turn on autoreload by default but before boot.py in case it wants to change it.
if (safe_mode == NO_SAFE_MODE) {
if (get_safe_mode() == SAFE_MODE_NONE) {
autoreload_enable();
}
// By default our internal flash is readonly to local python code and
// writable over USB. Set it here so that boot.py can change it.
// writable over USB. Set it here so that safemode.py or boot.py can change it.
filesystem_set_internal_concurrent_write_protection(true);
filesystem_set_internal_writable_by_usb(CIRCUITPY_USB == 1);
run_boot_py(safe_mode);
#if CIRCUITPY_SAFEMODE_PY
// Run safemode.py if we ARE in safe mode.
// If safemode.py does not do a hard reset, and exits normally, we will continue on
// and report the safe mode as usual.
run_safemode_py(get_safe_mode());
#endif
run_boot_py(get_safe_mode());
supervisor_workflow_start();
@ -1016,7 +1047,7 @@ int __attribute__((used)) main(void) {
// If code.py did a fake deep sleep, pretend that we
// are running code.py for the first time after a hard
// reset. This will preserve any alarm information.
skip_repl = run_code_py(safe_mode, &simulate_reset);
skip_repl = run_code_py(get_safe_mode(), &simulate_reset);
} else {
skip_repl = false;
}
@ -1076,14 +1107,14 @@ void gc_collect(void) {
}
void NORETURN nlr_jump_fail(void *val) {
reset_into_safe_mode(MICROPY_NLR_JUMP_FAIL);
reset_into_safe_mode(SAFE_MODE_NLR_JUMP_FAIL);
while (true) {
}
}
#ifndef NDEBUG
static void NORETURN __fatal_error(const char *msg) {
reset_into_safe_mode(MICROPY_FATAL_ERROR);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
}
}

View File

@ -23,7 +23,7 @@
#define CALIBRATE_CRYSTALLESS 1
// Explanation of how a user got into safe mode.
#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.")
// Increase stack size slightly due to CPX library import nesting
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8

View File

@ -23,7 +23,7 @@
#define CALIBRATE_CRYSTALLESS 1
// Explanation of how a user got into safe mode.
#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.")
// Increase stack size slightly due to CPX library import nesting
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8

View File

@ -23,7 +23,7 @@
#define CALIBRATE_CRYSTALLESS 1
// Explanation of how a user got into safe mode.
#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.")
// Increase stack size slightly due to CPX library import nesting.
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8

View File

@ -6,7 +6,7 @@
#define CALIBRATE_CRYSTALLESS 1
// Explanation of how a user got into safe mode.
#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.")
#define DEFAULT_I2C_BUS_SCL (&pin_PA01)
#define DEFAULT_I2C_BUS_SDA (&pin_PA00)

View File

@ -51,9 +51,8 @@ void common_hal_mcu_disable_interrupts(void) {
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// "HardFault".
HardFault_Handler();
// This is very very bad because it means there was mismatched disable/enables.
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -76,7 +75,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
_bootloader_dbl_tap = DBL_TAP_MAGIC_QUICK_BOOT;
}
if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
}

View File

@ -368,20 +368,20 @@ safe_mode_t port_init(void) {
#ifdef SAMD21
if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) {
return BROWNOUT;
return SAFE_MODE_BROWNOUT;
}
#endif
#ifdef SAM_D5X_E5X
if (RSTC->RCAUSE.bit.BODVDD == 1 || RSTC->RCAUSE.bit.BODCORE == 1) {
return BROWNOUT;
return SAFE_MODE_BROWNOUT;
}
#endif
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {
@ -720,7 +720,7 @@ __attribute__((used)) void HardFault_Handler(void) {
REG_MTB_MASTER = 0x00000000 + 6;
#endif
reset_into_safe_mode(HARD_CRASH);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}

View File

@ -46,7 +46,7 @@ void common_hal_mcu_disable_interrupts(void) {
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// reset_into_safe_mode(LOCKING_ERROR);
// reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {

View File

@ -78,10 +78,10 @@ safe_mode_t port_init(void) {
// Check brownout.
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {

View File

@ -74,7 +74,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
if (runmode == RUNMODE_BOOTLOADER) {
mp_raise_ValueError(translate("Cannot reset into bootloader because no bootloader is present"));
} else if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
}

View File

@ -66,10 +66,10 @@ safe_mode_t port_init(void) {
heap_size = size / sizeof(uint32_t);
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_cpu(void) {

View File

@ -47,7 +47,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO38)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The SW38 button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the SW38 button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -35,7 +35,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The VOLUME button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the VOLUME button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -38,7 +38,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -42,7 +42,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -42,7 +42,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -41,7 +41,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -42,7 +42,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -43,7 +43,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -39,7 +39,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO37)
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.")
// UART pins attached to the USB-serial converter chip
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)

View File

@ -108,7 +108,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
break;
case RUNMODE_SAFE_MODE:
// enter safe mode on next boot
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
break;
case RUNMODE_BOOTLOADER:
// DFU download

View File

@ -318,25 +318,25 @@ safe_mode_t port_init(void) {
}
if (heap == NULL) {
heap_size = 0;
return NO_HEAP;
return SAFE_MODE_NO_HEAP;
}
esp_reset_reason_t reason = esp_reset_reason();
switch (reason) {
case ESP_RST_BROWNOUT:
return BROWNOUT;
return SAFE_MODE_BROWNOUT;
case ESP_RST_PANIC:
return HARD_CRASH;
return SAFE_MODE_HARD_FAULT;
case ESP_RST_INT_WDT:
// The interrupt watchdog is used internally to make sure that latency sensitive
// interrupt code isn't blocked. User watchdog resets come through ESP_RST_WDT.
return WATCHDOG_RESET;
return SAFE_MODE_WATCHDOG;
case ESP_RST_WDT:
default:
break;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {

View File

@ -70,9 +70,8 @@ void common_hal_mcu_disable_interrupts(void) {
__attribute__((section(".ramtext")))
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// "HardFault".
asm ("ebreak");
// This is very very bad because it means there was mismatched disable/enables.
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -83,7 +82,7 @@ void common_hal_mcu_enable_interrupts(void) {
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
}

View File

@ -71,7 +71,7 @@ safe_mode_t port_init(void) {
irq_setmask(0);
irq_setie(1);
tick_init();
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
extern uint32_t _ebss;

View File

@ -52,12 +52,10 @@ void common_hal_mcu_disable_interrupts(void) {
nesting_count++;
}
void HardFault_Handler(void);
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// "HardFault".
HardFault_Handler();
// This is very very bad because it means there was mismatched disable/enables
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -80,7 +78,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
DBL_TAP_REG = DBL_TAP_MAGIC_QUICK_BOOT;
}
if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
}

View File

@ -259,10 +259,10 @@ safe_mode_t port_init(void) {
// run yet, which uses `never_reset` to protect critical pins from being reset by `reset_port`.
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {
@ -419,7 +419,7 @@ void port_idle_until_interrupt(void) {
*/
void MemManage_Handler(void);
__attribute__((used)) void MemManage_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
@ -430,7 +430,7 @@ __attribute__((used)) void MemManage_Handler(void) {
*/
void BusFault_Handler(void);
__attribute__((used)) void BusFault_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
@ -441,7 +441,7 @@ __attribute__((used)) void BusFault_Handler(void) {
*/
void UsageFault_Handler(void);
__attribute__((used)) void UsageFault_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
@ -452,7 +452,7 @@ __attribute__((used)) void UsageFault_Handler(void) {
*/
void HardFault_Handler(void);
__attribute__((used)) void HardFault_Handler(void) {
reset_into_safe_mode(HARD_CRASH);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}

View File

@ -52,7 +52,7 @@
#define CIRCUITPY_BOOT_BUTTON (&pin_P0_29)
#define BOARD_USER_SAFE_MODE_ACTION translate("The left button was pressed at start up.\n")
#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the left button at start up.")
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)

View File

@ -91,7 +91,7 @@ const nvm_bytearray_obj_t common_hal_bleio_nvm_obj = {
};
STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) {
reset_into_safe_mode(NORDIC_SOFT_DEVICE_ASSERT);
reset_into_safe_mode(SAFE_MODE_SDK_FATAL_ERROR);
}
bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];

View File

@ -68,9 +68,8 @@ void common_hal_mcu_disable_interrupts() {
void common_hal_mcu_enable_interrupts() {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// crash.
reset_into_safe_mode(HARD_CRASH);
// This is very very bad because it means there was mismatched disable/enables.
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -88,7 +87,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
sd_power_gpregret_set(0,0);
}
if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
}

View File

@ -75,7 +75,7 @@ void port_internal_flash_flush(void) {
// Skip if data is the same
if (memcmp(_flash_cache, (void *)_flash_page_addr, FLASH_PAGE_SIZE) != 0) {
if (!nrf_nvm_safe_flash_page_write(_flash_page_addr, _flash_cache)) {
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
}
}

View File

@ -77,7 +77,7 @@ extern void qspi_disable(void);
#endif
static void power_warning_handler(void) {
reset_into_safe_mode(BROWNOUT);
reset_into_safe_mode(SAFE_MODE_BROWNOUT);
}
uint32_t reset_reason_saved = 0;
@ -204,11 +204,11 @@ safe_mode_t port_init(void) {
// If USB is connected, then the user might be editing `code.py`,
// in which case we should reboot into Safe Mode.
if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) {
return WATCHDOG_RESET;
return SAFE_MODE_WATCHDOG;
}
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {
@ -399,7 +399,7 @@ void port_idle_until_interrupt(void) {
extern void HardFault_Handler(void);
void HardFault_Handler(void) {
reset_into_safe_mode(HARD_CRASH);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}

View File

@ -60,7 +60,7 @@ void common_hal_mcu_disable_interrupts(void) {
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// reset_into_safe_mode(LOCKING_ERROR);
// reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -79,7 +79,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
next_reset_to_bootloader = true;
break;
case RUNMODE_SAFE_MODE:
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
break;
default:
break;

View File

@ -161,10 +161,10 @@ safe_mode_t port_init(void) {
}
#endif
if (board_requests_safe_mode()) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_port(void) {
@ -312,7 +312,7 @@ __attribute__((used)) void HardFault_Handler(void) {
REG_MTB_MASTER = 0x00000000 + 6;
#endif
reset_into_safe_mode(HARD_CRASH);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}

View File

@ -105,8 +105,7 @@ STATIC int next_filter(canio_can_obj_t *can) {
return i;
}
}
reset_into_safe_mode(MICROPY_FATAL_ERROR);
return -1;
mp_raise_msg_varg(&mp_type_RuntimeError, translate("%q"), MP_QSTR_Listener);
}
// IDE = "extended ID" flag of packet header. We always add this bit to the

View File

@ -61,9 +61,8 @@ void common_hal_mcu_disable_interrupts(void) {
void common_hal_mcu_enable_interrupts(void) {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// "HardFault".
asm ("bkpt");
// This is very very bad because it means there was mismatched disable/enables.
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
}
nesting_count--;
if (nesting_count > 0) {
@ -77,7 +76,7 @@ static bool next_reset_to_bootloader = false;
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
if (runmode == RUNMODE_SAFE_MODE) {
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
}
if (runmode == RUNMODE_BOOTLOADER) {
next_reset_to_bootloader = true;

View File

@ -215,7 +215,7 @@ void port_internal_flash_flush(void) {
EraseInitStruct.NbSectors = 1;
#endif
if (sector_size > sizeof(_flash_cache) || sector_start_addr == 0xffffffff) {
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
// Skip if data is the same
@ -228,7 +228,7 @@ void port_internal_flash_flush(void) {
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
// error occurred during sector erase
HAL_FLASH_Lock(); // lock the flash
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
uint32_t *cache_addr = (uint32_t *)_flash_cache;
@ -240,7 +240,7 @@ void port_internal_flash_flush(void) {
(uint32_t)cache_addr) != HAL_OK) {
// error occurred during flash write
HAL_FLASH_Lock(); // lock the flash
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
// RAM memory is by word (4 byte), but flash memory is by byte
cache_addr += 8;
@ -253,7 +253,7 @@ void port_internal_flash_flush(void) {
*(uint64_t *)cache_addr) != HAL_OK) {
// error occurred during flash write
HAL_FLASH_Lock(); // lock the flash
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
// RAM memory is by word (4 byte), but flash memory is by byte
cache_addr += 2;
@ -267,7 +267,7 @@ void port_internal_flash_flush(void) {
(uint64_t)*cache_addr) != HAL_OK) {
// error occurred during flash write
HAL_FLASH_Lock(); // lock the flash
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
// RAM memory is by word (4 byte), but flash memory is by byte
cache_addr += 1;
@ -335,7 +335,7 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block_num,
// Fail for any sector outside what's supported by the cache
if (sector_size > sizeof(_flash_cache)) {
reset_into_safe_mode(FLASH_WRITE_FAIL);
reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL);
}
// Find how many blocks are left in the sector

View File

@ -211,7 +211,7 @@ safe_mode_t port_init(void) {
// Turn off SysTick
SysTick->CTRL = 0;
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void HAL_Delay(uint32_t delay_ms) {
@ -357,28 +357,28 @@ uint32_t port_get_saved_word(void) {
}
__attribute__((used)) void MemManage_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
}
__attribute__((used)) void BusFault_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
}
__attribute__((used)) void UsageFault_Handler(void) {
reset_into_safe_mode(MEM_MANAGE);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}
}
__attribute__((used)) void HardFault_Handler(void) {
reset_into_safe_mode(HARD_CRASH);
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
while (true) {
asm ("nop;");
}

View File

@ -525,6 +525,7 @@ $(filter $(SRC_PATTERNS), \
qrio/PixelPolicy.c \
qrio/QRInfo.c \
supervisor/RunReason.c \
supervisor/SafeModeReason.c \
supervisor/StatusBar.c \
wifi/AuthMode.c \
wifi/Packet.c \

View File

@ -372,6 +372,10 @@ CFLAGS += -DCIRCUITPY_ROTARYIO_SOFTENCODER=$(CIRCUITPY_ROTARYIO_SOFTENCODER)
CIRCUITPY_RTC ?= 1
CFLAGS += -DCIRCUITPY_RTC=$(CIRCUITPY_RTC)
# Enable support for safemode.py
CIRCUITPY_SAFEMODE_PY ?= 1
CFLAGS += -DCIRCUITPY_SAFEMODE_PY=$(CIRCUITPY_SAFEMODE_PY)
# CIRCUITPY_SAMD is handled in the atmel-samd tree.
# Only for SAMD chips.
# Assume not a SAMD build.

View File

@ -518,7 +518,7 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags, bool long_lived) {
}
if (MP_STATE_MEM(gc_pool_start) == 0) {
reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM);
}
GC_ENTER();
@ -712,7 +712,7 @@ void gc_free(void *ptr) {
GC_EXIT();
} else {
if (MP_STATE_MEM(gc_pool_start) == 0) {
reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM);
}
// get the GC block number corresponding to this pointer
assert(VERIFY_PTR(ptr));

View File

@ -42,7 +42,7 @@ MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_
//| """The reason the microntroller was last reset"""
//|
//| POWER_ON: object
//| """The microntroller was started from power off."""
//| """The microcontroller was started from power off."""
//|
//| BROWNOUT: object
//| """The microntroller was reset due to too low a voltage."""

View File

@ -32,6 +32,7 @@
#include "shared-bindings/supervisor/RunReason.h"
#include "shared-bindings/supervisor/Runtime.h"
#include "shared-bindings/supervisor/SafeModeReason.h"
#include "supervisor/shared/reload.h"
#include "supervisor/shared/stack.h"
@ -106,7 +107,7 @@ void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
}
//| run_reason: RunReason
//| """Why CircuitPython started running this particular time."""
//| """Why CircuitPython started running this particular time (read-only)."""
STATIC mp_obj_t supervisor_runtime_get_run_reason(mp_obj_t self) {
return cp_enum_find(&supervisor_run_reason_type, _run_reason);
}
@ -115,6 +116,20 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_run_reason_obj, supervisor_runt
MP_PROPERTY_GETTER(supervisor_runtime_run_reason_obj,
(mp_obj_t)&supervisor_runtime_get_run_reason_obj);
//| safe_mode_reason: SafeModeReason
//| """Why CircuitPython went into safe mode this particular time (read-only)."""
STATIC mp_obj_t supervisor_runtime_get_safe_mode_reason(mp_obj_t self) {
#if CIRCUITPY_SAFEMODE_PY
return cp_enum_find(&supervisor_safe_mode_reason_type, get_safe_mode());
#else
mp_raise_NotImplementedError(NULL);
#endif
}
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_safe_mode_reason_obj, supervisor_runtime_get_safe_mode_reason);
MP_PROPERTY_GETTER(supervisor_runtime_safe_mode_reason_obj,
(mp_obj_t)&supervisor_runtime_get_safe_mode_reason_obj);
//| autoreload: bool
//| """Whether CircuitPython may autoreload based on workflow writes to the filesystem."""
//|
@ -218,6 +233,7 @@ STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) },
{ MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_runtime_serial_bytes_available_obj) },
{ MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_runtime_run_reason_obj) },
{ MP_ROM_QSTR(MP_QSTR_safe_mode_reason), MP_ROM_PTR(&supervisor_runtime_safe_mode_reason_obj) },
{ MP_ROM_QSTR(MP_QSTR_autoreload), MP_ROM_PTR(&supervisor_runtime_autoreload_obj) },
{ MP_ROM_QSTR(MP_QSTR_ble_workflow), MP_ROM_PTR(&supervisor_runtime_ble_workflow_obj) },
{ MP_ROM_QSTR(MP_QSTR_next_stack_limit), MP_ROM_PTR(&supervisor_runtime_next_stack_limit_obj) },

View File

@ -31,12 +31,16 @@
#include "py/obj.h"
#include "shared-bindings/supervisor/RunReason.h"
#include "shared-bindings/supervisor/SafeModeReason.h"
extern const mp_obj_type_t supervisor_runtime_type;
supervisor_run_reason_t supervisor_get_run_reason(void);
void supervisor_set_run_reason(supervisor_run_reason_t run_reason);
safe_mode_t supervisor_get_safe_mode(void);
void supervisor_set_safe_mode(safe_mode_t safe_mode);
bool common_hal_supervisor_runtime_get_serial_connected(void);
bool common_hal_supervisor_runtime_get_serial_bytes_available(void);

View File

@ -0,0 +1,156 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Dan Halbert for Adafruit Industries
*
* 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/enum.h"
#include "shared-bindings/supervisor/SafeModeReason.h"
// Reuse the non-Python safe_mode_t enum
#include "supervisor/shared/safe_mode.h"
#if CIRCUITPY_SAFEMODE_PY
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, NONE, SAFE_MODE_NONE);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, BROWNOUT, SAFE_MODE_BROWNOUT);
// alphabetical from here down
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, FLASH_WRITE_FAIL, SAFE_MODE_FLASH_WRITE_FAIL);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, GC_ALLOC_OUTSIDE_VM, SAFE_MODE_GC_ALLOC_OUTSIDE_VM);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, HARD_FAULT, SAFE_MODE_HARD_FAULT);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, INTERRUPT_ERROR, SAFE_MODE_INTERRUPT_ERROR);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, NLR_JUMP_FAIL, SAFE_MODE_NLR_JUMP_FAIL);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, NO_CIRCUITPY, SAFE_MODE_NO_CIRCUITPY);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, NO_HEAP, SAFE_MODE_NO_HEAP);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, PROGRAMMATIC, SAFE_MODE_PROGRAMMATIC);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, SDK_FATAL_ERROR, SAFE_MODE_SDK_FATAL_ERROR);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, STACK_OVERFLOW, SAFE_MODE_STACK_OVERFLOW);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, USB_BOOT_DEVICE_NOT_INTERFACE_ZERO, SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, USB_TOO_MANY_ENDPOINTS, SAFE_MODE_USB_TOO_MANY_ENDPOINTS);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, USB_TOO_MANY_INTERFACE_NAMES, SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, USER, SAFE_MODE_USER);
MAKE_ENUM_VALUE(supervisor_safe_mode_reason_type, safe_mode_reason, WATCHDOG, SAFE_MODE_WATCHDOG);
#endif
//| class SafeModeReason:
//| """The reason that CircuitPython went into safe mode."""
//|
MAKE_ENUM_MAP(supervisor_safe_mode_reason) {
#if CIRCUITPY_SAFEMODE_PY
//| NONE: object
//| """CircuitPython is not in safe mode."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, NONE),
//| BROWNOUT: object
//| """The microcontroller voltage dropped too low."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, BROWNOUT),
// alphabetical from here down
//| FLASH_WRITE_FAIL: object
//| """Could not write to flash memory."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, FLASH_WRITE_FAIL),
//| GC_ALLOC_OUTSIDE_VM: object
//| """CircuitPython tried to allocate storage when its virtual machine was not running."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, GC_ALLOC_OUTSIDE_VM),
//| HARD_FAULT: object
//| """The microcontroller detected a fault, such as an out-of-bounds memory write."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, HARD_FAULT),
//| INTERRUPT_ERROR: object
//| """Internal error related to interrupts."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, INTERRUPT_ERROR),
//| NLR_JUMP_FAIL: object
//| """An error occurred during exception handling, possibly due to memory corruption."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, NLR_JUMP_FAIL),
//| NO_CIRCUITPY: object
//| """The CIRCUITPY drive was not available."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, NO_CIRCUITPY),
//| NO_HEAP: object
//| """Heap storage was not present."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, NO_HEAP),
//| PROGRAMMATIC: object
//| """The program entered safe mode using the `supervisor` module."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, PROGRAMMATIC),
//| SDK_FATAL_ERROR: object
//| """Third party firmware reported a fatal error."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, SDK_FATAL_ERROR),
//| STACK_OVERFLOW: object
//| """The CircuitPython heap was corrupted because the stack was too small."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, STACK_OVERFLOW),
//| USB_BOOT_DEVICE_NOT_INTERFACE_ZERO: object
//| """The USB HID boot device was not set up to be the first device, on interface #0."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, USB_BOOT_DEVICE_NOT_INTERFACE_ZERO),
//| USB_TOO_MANY_ENDPOINTS: object
//| """USB devices need more endpoints than are available."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, USB_TOO_MANY_ENDPOINTS),
//| USB_TOO_MANY_INTERFACE_NAMES: object
//| """USB devices specify too many interface names."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, USB_TOO_MANY_INTERFACE_NAMES),
//| USER: object
//| """The user pressed one or more buttons to enter safe mode."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, USER),
//| SAFE_MODE_WATCHDOG: object
//| """An internal watchdog timer expired."""
//|
MAKE_ENUM_MAP_ENTRY(safe_mode_reason, WATCHDOG),
#endif
};
STATIC MP_DEFINE_CONST_DICT(supervisor_safe_mode_reason_locals_dict, supervisor_safe_mode_reason_locals_table);
MAKE_PRINTER(supervisor, supervisor_safe_mode_reason);
MAKE_ENUM_TYPE(supervisor, SafeModeReason, supervisor_safe_mode_reason);

View File

@ -0,0 +1,31 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Dan Halbert for Adafruit Industries
*
* 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.
*/
#pragma once
#include "supervisor/shared/safe_mode.h"
extern const mp_obj_type_t supervisor_safe_mode_reason_type;

View File

@ -336,6 +336,11 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) },
{ MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) },
{ MP_ROM_QSTR(MP_QSTR_RunReason), MP_ROM_PTR(&supervisor_run_reason_type) },
#if CIRCUITPY_SAFEMODE_PY
{ MP_ROM_QSTR(MP_QSTR_SafeModeReason), MP_ROM_PTR(&supervisor_safe_mode_reason_type) },
#else
{ MP_ROM_QSTR(MP_QSTR_SafeModeReason), mp_const_none },
#endif
{ MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) },
{ MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&supervisor_ticks_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },

View File

@ -1,99 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* 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_SUPERVISOR_MESSAGES_DEFAULT_H
#define MICROPY_SUPERVISOR_MESSAGES_DEFAULT_H
#ifndef MSG_OUTPUT_SUFFIX
#define MSG_OUTPUT_SUFFIX " output:\r\n"
#endif
#ifndef MSG_NEWLINE
#define MSG_NEWLINE "\r\n"
#endif
#ifndef MSG_AUTORELOAD_ON
#define MSG_AUTORELOAD_ON "Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\r\n"
#endif
#ifndef MSG_AUTORELOAD_OFF
#define MSG_AUTORELOAD_OFF "Auto-reload is off.\r\n"
#endif
#ifndef MSG_SAFE_MODE_ON
#define MSG_SAFE_MODE_ON "Running in safe mode! Auto-reload is off.\r\n"
#endif
#ifndef MSG_SAFE_MODE_NO_MAIN
#define MSG_SAFE_MODE_NO_MAIN "Running in safe mode! Not running saved code.\r\n"
#endif
#ifndef MSG_SAFE_MODE_USER_REQUESTED
#define MSG_SAFE_MODE_USER_REQUESTED "You requested starting safe mode by "
#endif
#ifndef MSG_SAFE_MODE_USER_EXIT
#define MSG_SAFE_MODE_USER_EXIT "To exit, please reset the board without "
#endif
#ifndef MSG_BAD_SAFE_MODE
#define MSG_BAD_SAFE_MODE "You are running in safe mode which means something really bad happened."
#endif
#ifndef MSG_SAFE_MODE_CRASH
#define MSG_SAFE_MODE_CRASH "Looks like our core CircuitPython code crashed hard. Whoops!"
#endif
#ifndef MSG_SAFE_MODE_FILE_ISSUE
#define MSG_SAFE_MODE_FILE_ISSUE "Please file an issue here with the contents of your CIRCUITPY drive:"
#endif
#ifndef MSG_SAFE_MODE_ISSUE_LINK
#define MSG_SAFE_MODE_ISSUE_LINK "https://github.com/adafruit/circuitpython/issues"
#endif
#ifndef MSG_SAFE_MODE_BROWN_OUT_LINE_1
#define MSG_SAFE_MODE_BROWN_OUT_LINE_1 "The microcontroller's power dipped. Please make sure your power supply provides"
#endif
#ifndef MSG_SAFE_MODE_BROWN_OUT_LINE_2
#define MSG_SAFE_MODE_BROWN_OUT_LINE_2 "enough power for the whole circuit and press reset (after ejecting CIRCUITPY)."
#endif
#ifndef MSG_WAIT_BEFORE_REPL
#define MSG_WAIT_BEFORE_REPL "Press any key to enter the REPL. Use CTRL-D to reload."
#endif
// Be careful, some tools depend on this.
#ifndef MSG_SOFT_REBOOT
#define MSG_SOFT_REBOOT "soft reboot"
#endif
#ifndef MSG_DOUBLE_FILE_EXTENSION
#define MSG_DOUBLE_FILE_EXTENSION "WARNING: Your code filename has two extensions\r\n"
#endif
#endif // MICROPY_SUPERVISOR_MESSAGES_DEFAULT_H

View File

@ -43,20 +43,28 @@
#define SAFE_MODE_DATA_GUARD 0xad0000af
#define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff
static safe_mode_t current_safe_mode;
static safe_mode_t _safe_mode;
safe_mode_t get_safe_mode(void) {
return _safe_mode;
}
void set_safe_mode(safe_mode_t safe_mode) {
_safe_mode = safe_mode;
}
safe_mode_t wait_for_safe_mode_reset(void) {
uint32_t reset_state = port_get_saved_word();
safe_mode_t safe_mode = NO_SAFE_MODE;
safe_mode_t safe_mode = SAFE_MODE_NONE;
if ((reset_state & SAFE_MODE_DATA_GUARD_MASK) == SAFE_MODE_DATA_GUARD) {
safe_mode = (reset_state & ~SAFE_MODE_DATA_GUARD_MASK) >> 8;
}
if (safe_mode != NO_SAFE_MODE) {
if (safe_mode != SAFE_MODE_NONE) {
port_set_saved_word(SAFE_MODE_DATA_GUARD);
current_safe_mode = safe_mode;
_safe_mode = safe_mode;
return safe_mode;
} else {
current_safe_mode = 0;
_safe_mode = SAFE_MODE_NONE;
}
const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason();
@ -64,12 +72,12 @@ safe_mode_t wait_for_safe_mode_reset(void) {
reset_reason != RESET_REASON_RESET_PIN &&
reset_reason != RESET_REASON_UNKNOWN &&
reset_reason != RESET_REASON_SOFTWARE) {
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
#if CIRCUITPY_SKIP_SAFE_MODE_WAIT
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
#endif
port_set_saved_word(SAFE_MODE_DATA_GUARD | (MANUAL_SAFE_MODE << 8));
port_set_saved_word(SAFE_MODE_DATA_GUARD | (SAFE_MODE_USER << 8));
// Wait for a while to allow for reset.
#if CIRCUITPY_STATUS_LED
@ -106,11 +114,11 @@ safe_mode_t wait_for_safe_mode_reset(void) {
status_led_deinit();
#endif
if (boot_in_safe_mode) {
return USER_SAFE_MODE;
return SAFE_MODE_USER;
}
// Restore the original state of the saved word if no reset occured during our wait period.
port_set_saved_word(reset_state);
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void safe_mode_on_next_reset(safe_mode_t reason) {
@ -119,7 +127,7 @@ void safe_mode_on_next_reset(safe_mode_t reason) {
// Don't inline this so it's easy to break on it from GDB.
void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) {
if (current_safe_mode > BROWNOUT && reason > BROWNOUT) {
if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) {
while (true) {
// This very bad because it means running in safe mode didn't save us. Only ignore brownout
// because it may be due to a switch bouncing.
@ -133,7 +141,7 @@ void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) {
void print_safe_mode_message(safe_mode_t reason) {
if (reason == NO_SAFE_MODE) {
if (reason == SAFE_MODE_NONE) {
return;
}
@ -145,43 +153,42 @@ void print_safe_mode_message(safe_mode_t reason) {
// First check for safe mode reasons that do not necessarily reflect bugs.
switch (reason) {
case USER_SAFE_MODE:
case SAFE_MODE_BROWNOUT:
message = translate("The microcontroller's power dipped. Make sure your power supply provides\nenough power for the whole circuit and press reset (after ejecting CIRCUITPY).");
break;
case SAFE_MODE_USER:
#if defined(BOARD_USER_SAFE_MODE_ACTION)
message = BOARD_USER_SAFE_MODE_ACTION;
#elif defined(CIRCUITPY_BOOT_BUTTON)
message = translate("The BOOT button was pressed at start up.\n");
message = translate("You pressed the BOOT button at start up.");
#else
message = translate("You pressed the reset button during boot.");
#endif
#if defined(BOARD_USER_SAFE_MODE_ACTION) || defined(CIRCUITPY_BOOT_BUTTON)
// Output a user safe mode string if it's set.
serial_write_compressed(message);
message = translate("To exit, please reset the board without requesting safe mode.");
message = translate("\nTo exit, reset the board without requesting safe mode.");
// The final piece is printed below.
#endif
break;
case MANUAL_SAFE_MODE:
message = translate("You pressed the reset button during boot. Press again to exit safe mode.");
case SAFE_MODE_NO_CIRCUITPY:
message = translate("CIRCUITPY drive could not be found or created.");
break;
case PROGRAMMATIC_SAFE_MODE:
case SAFE_MODE_PROGRAMMATIC:
message = translate("The `microcontroller` module was used to boot into safe mode. Press reset to exit safe mode.");
break;
case BROWNOUT:
message = translate("The microcontroller's power dipped. Make sure your power supply provides\nenough power for the whole circuit and press reset (after ejecting CIRCUITPY).");
case SAFE_MODE_SAFEMODE_PY_ERROR:
message = translate("Error in safemode.py.");
break;
case USB_TOO_MANY_ENDPOINTS:
case SAFE_MODE_USB_TOO_MANY_ENDPOINTS:
message = translate("USB devices need more endpoints than are available.");
break;
case USB_TOO_MANY_INTERFACE_NAMES:
case SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES:
message = translate("USB devices specify too many interface names.");
break;
case USB_BOOT_DEVICE_NOT_INTERFACE_ZERO:
case SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO:
message = translate("Boot device must be first device (interface #0).");
break;
case WATCHDOG_RESET:
case SAFE_MODE_WATCHDOG:
message = translate("Internal watchdog timer expired.");
break;
case NO_CIRCUITPY:
message = translate("CIRCUITPY drive could not be found or created.");
break;
default:
break;
}
@ -197,36 +204,29 @@ void print_safe_mode_message(safe_mode_t reason) {
serial_write_compressed(translate("CircuitPython core code crashed hard. Whoops!\n"));
switch (reason) {
case HARD_CRASH:
message = translate("Crash into the HardFault_Handler.");
break;
case MICROPY_NLR_JUMP_FAIL:
message = translate("NLR jump failed. Likely memory corruption.");
break;
case MICROPY_FATAL_ERROR:
message = translate("Fatal error.");
break;
case NO_HEAP:
message = translate("CircuitPython was unable to allocate the heap.");
break;
case HEAP_OVERWRITTEN:
message = translate("The CircuitPython heap was corrupted because the stack was too small.\nIncrease the stack size if you know how. If not:");
break;
case GC_ALLOC_OUTSIDE_VM:
case SAFE_MODE_GC_ALLOC_OUTSIDE_VM:
message = translate("Attempted heap allocation when VM not running.");
break;
#ifdef SOFTDEVICE_PRESENT
// defined in ports/nrf/bluetooth/bluetooth_common.mk
// will print "Unknown reason" if somehow encountered on other ports
case NORDIC_SOFT_DEVICE_ASSERT:
message = translate("Nordic system firmware failure assertion.");
break;
#endif
case FLASH_WRITE_FAIL:
case SAFE_MODE_FLASH_WRITE_FAIL:
message = translate("Failed to write internal flash.");
break;
case MEM_MANAGE:
message = translate("Invalid memory access.");
case SAFE_MODE_HARD_FAULT:
message = translate("Crash into the HardFault_Handler.");
break;
case SAFE_MODE_INTERRUPT_ERROR:
message = translate("Interrupt error.");
break;
case SAFE_MODE_NLR_JUMP_FAIL:
message = translate("NLR jump failed. Likely memory corruption.");
break;
case SAFE_MODE_NO_HEAP:
message = translate("CircuitPython was unable to allocate the heap.");
break;
case SAFE_MODE_SDK_FATAL_ERROR:
message = translate("Third-party firmware fatal error.");
break;
case SAFE_MODE_STACK_OVERFLOW:
message = translate("The CircuitPython heap was corrupted because the stack was too small.\nIncrease the stack size if you know how. If not:");
break;
default:
message = translate("Unknown reason.");

View File

@ -30,27 +30,32 @@
#include "py/mpconfig.h"
typedef enum {
NO_SAFE_MODE = 0,
BROWNOUT,
HARD_CRASH,
USER_SAFE_MODE,
HEAP_OVERWRITTEN,
MANUAL_SAFE_MODE,
MICROPY_NLR_JUMP_FAIL,
MICROPY_FATAL_ERROR,
GC_ALLOC_OUTSIDE_VM,
PROGRAMMATIC_SAFE_MODE,
NORDIC_SOFT_DEVICE_ASSERT,
FLASH_WRITE_FAIL,
MEM_MANAGE,
WATCHDOG_RESET,
USB_TOO_MANY_ENDPOINTS,
USB_TOO_MANY_INTERFACE_NAMES,
USB_BOOT_DEVICE_NOT_INTERFACE_ZERO,
NO_HEAP,
NO_CIRCUITPY,
SAFE_MODE_NONE = 0,
// BROWNOUT should be lowest after SAFE_MODE_NONE.
SAFE_MODE_BROWNOUT,
// alphabetical from here down
SAFE_MODE_FLASH_WRITE_FAIL,
SAFE_MODE_GC_ALLOC_OUTSIDE_VM,
SAFE_MODE_HARD_FAULT,
SAFE_MODE_INTERRUPT_ERROR,
SAFE_MODE_MANUAL,
SAFE_MODE_NLR_JUMP_FAIL,
SAFE_MODE_NO_CIRCUITPY,
SAFE_MODE_NO_HEAP,
SAFE_MODE_PROGRAMMATIC,
SAFE_MODE_SAFEMODE_PY_ERROR,
SAFE_MODE_SDK_FATAL_ERROR,
SAFE_MODE_STACK_OVERFLOW,
SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO,
SAFE_MODE_USB_TOO_MANY_ENDPOINTS,
SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES,
SAFE_MODE_USER,
SAFE_MODE_WATCHDOG,
} safe_mode_t;
safe_mode_t get_safe_mode(void);
void set_safe_mode(safe_mode_t safe_mode);
safe_mode_t wait_for_safe_mode_reset(void);
void safe_mode_on_next_reset(safe_mode_t reason);

View File

@ -74,7 +74,7 @@ inline bool stack_ok(void) {
inline void assert_heap_ok(void) {
if (!stack_ok()) {
reset_into_safe_mode(HEAP_OVERWRITTEN);
reset_into_safe_mode(SAFE_MODE_STACK_OVERFLOW);
}
}

View File

@ -228,7 +228,7 @@ static void usb_build_configuration_descriptor(void) {
if (usb_hid_boot_device() > 0 && descriptor_counts.current_interface > 0) {
// Hosts using boot devices generally to expect them to be at interface zero,
// and will not work properly otherwise.
reset_into_safe_mode(USB_BOOT_DEVICE_NOT_INTERFACE_ZERO);
reset_into_safe_mode(SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO);
}
descriptor_buf_remaining += usb_hid_add_descriptor(
descriptor_buf_remaining, &descriptor_counts, &current_interface_string,
@ -258,14 +258,14 @@ static void usb_build_configuration_descriptor(void) {
if (descriptor_counts.current_endpoint > USB_NUM_ENDPOINT_PAIRS ||
descriptor_counts.num_in_endpoints > USB_NUM_IN_ENDPOINTS ||
descriptor_counts.num_out_endpoints > USB_NUM_OUT_ENDPOINTS) {
reset_into_safe_mode(USB_TOO_MANY_ENDPOINTS);
reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_ENDPOINTS);
}
}
// str must not be on the heap.
void usb_add_interface_string(uint8_t interface_string_index, const char str[]) {
if (interface_string_index > MAX_INTERFACE_STRINGS) {
reset_into_safe_mode(USB_TOO_MANY_INTERFACE_NAMES);
reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES);
}
collected_interface_strings[interface_string_index].char_str = str;

View File

@ -29,7 +29,7 @@
#include <stdlib.h>
safe_mode_t wait_for_safe_mode_reset(void) {
return NO_SAFE_MODE;
return SAFE_MODE_NONE;
}
void reset_into_safe_mode(safe_mode_t reason) {