Merge pull request #7577 from dhalbert/safemode-py
Implement safemode.py
This commit is contained in:
commit
bbadc00599
16
README.rst
16
README.rst
|
@ -138,6 +138,16 @@ Behavior
|
||||||
- Adds a safe mode that does not run user code after a hard crash or brown out. This makes it
|
- 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
|
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.
|
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, unless the safe mode
|
||||||
|
initiated by the user by pressing button(s).
|
||||||
|
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.
|
- RGB status LED indicating CircuitPython state.
|
||||||
- One green flash - code completed without error.
|
- One green flash - code completed without error.
|
||||||
- Two red flashes - code ended due to an exception.
|
- Two red flashes - code ended due to an exception.
|
||||||
|
@ -145,9 +155,9 @@ Behavior
|
||||||
- Re-runs ``code.py`` or other main file after file system writes by a workflow. (Disable with
|
- Re-runs ``code.py`` or other main file after file system writes by a workflow. (Disable with
|
||||||
``supervisor.disable_autoreload()``)
|
``supervisor.disable_autoreload()``)
|
||||||
- Autoreload is disabled while the REPL is active.
|
- Autoreload is disabled while the REPL is active.
|
||||||
- Main is one of these: ``code.txt``, ``code.py``, ``main.py``,
|
- ``code.py`` may also be named``code.txt``, ``main.py``, or ``main.txt``.
|
||||||
``main.txt``
|
- ``boot.py`` may also be named ``boot.txt``.
|
||||||
- Boot is one of these: ``boot.py``, ``boot.txt``
|
- ``safemode.py`` may also be named ``safemode.txt``.
|
||||||
|
|
||||||
API
|
API
|
||||||
~~~
|
~~~
|
||||||
|
|
|
@ -31,8 +31,20 @@ msgstr ""
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"Please file an issue with the contents of your CIRCUITPY drive at \n"
|
"Please file an issue with your program at https://github.com/adafruit/"
|
||||||
"https://github.com/adafruit/circuitpython/issues\n"
|
"circuitpython/issues."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
"Press reset to exit safe mode.\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
"You are in safe mode because:\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
|
@ -85,7 +97,7 @@ msgstr ""
|
||||||
#: ports/raspberrypi/common-hal/alarm/__init__.c
|
#: ports/raspberrypi/common-hal/alarm/__init__.c
|
||||||
#: ports/raspberrypi/common-hal/analogio/AnalogOut.c
|
#: ports/raspberrypi/common-hal/analogio/AnalogOut.c
|
||||||
#: ports/raspberrypi/common-hal/rtc/RTC.c ports/stm/common-hal/alarm/__init__.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"
|
msgid "%q"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -530,10 +542,6 @@ msgstr ""
|
||||||
msgid "Attempt to allocate %d blocks"
|
msgid "Attempt to allocate %d blocks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
|
||||||
msgid "Attempted heap allocation when VM not running."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/raspberrypi/audio_dma.c
|
#: ports/raspberrypi/audio_dma.c
|
||||||
msgid "Audio conversion not implemented"
|
msgid "Audio conversion not implemented"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -582,20 +590,13 @@ msgid "Bitmap size and bits per value must match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid "Boot device must be first device (interface #0)."
|
msgid "Boot device must be first (interface #0)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ports/mimxrt10xx/common-hal/busio/UART.c
|
#: ports/mimxrt10xx/common-hal/busio/UART.c
|
||||||
msgid "Both RX and TX required for flow control"
|
msgid "Both RX and TX required for flow control"
|
||||||
msgstr ""
|
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
|
#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
|
||||||
msgid "Both pins must support hardware interrupts"
|
msgid "Both pins must support hardware interrupts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -661,12 +662,6 @@ msgstr ""
|
||||||
msgid "Bus pin %d is already in use"
|
msgid "Bus pin %d is already in use"
|
||||||
msgstr ""
|
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
|
#: shared-bindings/_bleio/UUID.c
|
||||||
msgid "Byte buffer must be 16 bytes."
|
msgid "Byte buffer must be 16 bytes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -797,10 +792,6 @@ msgstr ""
|
||||||
msgid "CircuitPython core code crashed hard. Whoops!\n"
|
msgid "CircuitPython core code crashed hard. Whoops!\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
|
||||||
msgid "CircuitPython was unable to allocate the heap."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: shared-module/bitbangio/I2C.c
|
#: shared-module/bitbangio/I2C.c
|
||||||
msgid "Clock stretch too long"
|
msgid "Clock stretch too long"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -839,10 +830,6 @@ msgstr ""
|
||||||
msgid "Couldn't allocate decoder"
|
msgid "Couldn't allocate decoder"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
|
||||||
msgid "Crash into the HardFault_Handler."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/stm/common-hal/analogio/AnalogOut.c
|
#: ports/stm/common-hal/analogio/AnalogOut.c
|
||||||
msgid "DAC Channel Init Error"
|
msgid "DAC Channel Init Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -934,6 +921,10 @@ msgstr ""
|
||||||
msgid "Error in regex"
|
msgid "Error in regex"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid "Error in safemode.py."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c
|
#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c
|
||||||
msgid "Error: Failure to bind"
|
msgid "Error: Failure to bind"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1007,7 +998,7 @@ msgid "Failed to write internal flash."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid "Fatal error."
|
msgid "Fault detected by hardware."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/moduerrno.c
|
#: py/moduerrno.c
|
||||||
|
@ -1095,6 +1086,15 @@ msgstr ""
|
||||||
msgid "Hardware in use, try alternative pins"
|
msgid "Hardware in use, try alternative pins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid "Heap allocation when VM not running."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid ""
|
||||||
|
"Heap was corrupted because the stack was too small. Increase stack size."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/vfs_posix_file.c py/objstringio.c
|
#: extmod/vfs_posix_file.c py/objstringio.c
|
||||||
msgid "I/O operation on closed file"
|
msgid "I/O operation on closed file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1209,6 +1209,10 @@ msgstr ""
|
||||||
msgid "Internal watchdog timer expired."
|
msgid "Internal watchdog timer expired."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid "Interrupt error."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/argcheck.c shared-bindings/digitalio/DigitalInOut.c
|
#: py/argcheck.c shared-bindings/digitalio/DigitalInOut.c
|
||||||
msgid "Invalid %q"
|
msgid "Invalid %q"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1257,10 +1261,6 @@ msgstr ""
|
||||||
msgid "Invalid format chunk size"
|
msgid "Invalid format chunk size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
|
||||||
msgid "Invalid memory access."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/espressif/common-hal/wifi/Radio.c
|
#: ports/espressif/common-hal/wifi/Radio.c
|
||||||
msgid "Invalid multicast MAC address"
|
msgid "Invalid multicast MAC address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1549,10 +1549,6 @@ msgstr ""
|
||||||
msgid "No timer available"
|
msgid "No timer available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
|
||||||
msgid "Nordic system firmware failure assertion."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/nrf/common-hal/_bleio/__init__.c
|
#: ports/nrf/common-hal/_bleio/__init__.c
|
||||||
msgid "Nordic system firmware out of memory"
|
msgid "Nordic system firmware out of memory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2004,53 +2000,19 @@ msgid "Temperature read timed out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid "The BOOT button was pressed at start up.\n"
|
msgid "The `microcontroller` module was used to boot into safe mode."
|
||||||
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 "
|
|
||||||
"exit safe mode."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "The above exception was the direct cause of the following exception:"
|
msgid "The above exception was the direct cause of the following exception:"
|
||||||
msgstr ""
|
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
|
#: shared-bindings/rgbmatrix/RGBMatrix.c
|
||||||
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
|
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid ""
|
msgid "The power dipped. Make sure you are providing enough power."
|
||||||
"The microcontroller's power dipped. Make sure your power supply provides\n"
|
|
||||||
"enough power for the whole circuit and press reset (after ejecting "
|
|
||||||
"CIRCUITPY)."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: shared-module/audiomixer/MixerVoice.c
|
#: shared-module/audiomixer/MixerVoice.c
|
||||||
|
@ -2069,6 +2031,10 @@ msgstr ""
|
||||||
msgid "The sample's signedness does not match the mixer's"
|
msgid "The sample's signedness does not match the mixer's"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid "Third-party firmware fatal error."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: shared-module/imagecapture/ParallelImageCapture.c
|
#: shared-module/imagecapture/ParallelImageCapture.c
|
||||||
msgid "This microcontroller does not support continuous capture."
|
msgid "This microcontroller does not support continuous capture."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2101,10 +2067,6 @@ msgstr ""
|
||||||
msgid "Timeout is too long: Maximum timeout length is %d seconds"
|
msgid "Timeout is too long: Maximum timeout length is %d seconds"
|
||||||
msgstr ""
|
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
|
#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c
|
||||||
msgid "Too many channels in sample"
|
msgid "Too many channels in sample"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2196,6 +2158,10 @@ msgstr ""
|
||||||
msgid "Unable to allocate buffers for signed conversion"
|
msgid "Unable to allocate buffers for signed conversion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: supervisor/shared/safe_mode.c
|
||||||
|
msgid "Unable to allocate the heap."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/common-hal/busio/I2C.c
|
#: ports/espressif/common-hal/busio/I2C.c
|
||||||
msgid "Unable to create lock"
|
msgid "Unable to create lock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2401,13 +2367,44 @@ msgstr ""
|
||||||
msgid "Writes not supported on Characteristic"
|
msgid "Writes not supported on Characteristic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
|
||||||
msgid "You are in safe mode because:\n"
|
#: 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 ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid ""
|
msgid "You pressed the BOOT button at start up"
|
||||||
"You pressed the reset button during boot. Press again to exit safe mode."
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/micropython.c
|
#: supervisor/shared/micropython.c
|
||||||
|
|
67
main.c
67
main.c
|
@ -358,7 +358,7 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
|
||||||
} else {
|
} else {
|
||||||
serial_write_compressed(translate("Auto-reload is off.\n"));
|
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"));
|
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
|
// Do the filesystem flush check before reload in case another write comes
|
||||||
// in while we're doing the flush.
|
// in while we're doing the flush.
|
||||||
if (safe_mode == NO_SAFE_MODE) {
|
if (safe_mode == SAFE_MODE_NONE) {
|
||||||
stack_resize();
|
stack_resize();
|
||||||
filesystem_flush();
|
filesystem_flush();
|
||||||
}
|
}
|
||||||
if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) {
|
if (safe_mode == SAFE_MODE_NONE && !autoreload_pending()) {
|
||||||
static const char *const supported_filenames[] = {
|
static const char *const supported_filenames[] = {
|
||||||
"code.txt", "code.py", "main.py", "main.txt"
|
"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
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (_exec_result.return_code != PYEXEC_EXCEPTION) {
|
if (_exec_result.return_code != PYEXEC_EXCEPTION) {
|
||||||
if (safe_mode == NO_SAFE_MODE) {
|
if (safe_mode == SAFE_MODE_NONE) {
|
||||||
color = ALL_DONE;
|
color = ALL_DONE;
|
||||||
blink_count = ALL_DONE_BLINKS;
|
blink_count = ALL_DONE_BLINKS;
|
||||||
} else {
|
} else {
|
||||||
|
@ -730,8 +730,34 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) {
|
||||||
|
|
||||||
vstr_t *boot_output;
|
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.
|
||||||
|
// Also don't run if it's a user-initiated safemode (pressing button(s) during boot),
|
||||||
|
// since that's deliberate.
|
||||||
|
if (safe_mode == SAFE_MODE_NONE || safe_mode == SAFE_MODE_USER || !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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +765,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.
|
// There is USB setup to do even if boot.py is not actually run.
|
||||||
const bool ok_to_run = filesystem_present()
|
const bool ok_to_run = filesystem_present()
|
||||||
&& safe_mode == NO_SAFE_MODE
|
&& safe_mode == SAFE_MODE_NONE
|
||||||
&& MP_STATE_VM(vfs_mount_table) != NULL;
|
&& MP_STATE_VM(vfs_mount_table) != NULL;
|
||||||
|
|
||||||
static const char *const boot_py_filenames[] = {"boot.py", "boot.txt"};
|
static const char *const boot_py_filenames[] = {"boot.py", "boot.txt"};
|
||||||
|
@ -913,7 +939,7 @@ STATIC int run_repl(void) {
|
||||||
|
|
||||||
int __attribute__((used)) main(void) {
|
int __attribute__((used)) main(void) {
|
||||||
// initialise the cpu and peripherals
|
// 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.
|
// Turn on RX and TX LEDs if we have them.
|
||||||
init_rxtx_leds();
|
init_rxtx_leds();
|
||||||
|
@ -929,8 +955,8 @@ int __attribute__((used)) main(void) {
|
||||||
serial_early_init();
|
serial_early_init();
|
||||||
|
|
||||||
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
|
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
|
||||||
if (safe_mode == NO_SAFE_MODE) {
|
if (get_safe_mode() == SAFE_MODE_NONE) {
|
||||||
safe_mode = wait_for_safe_mode_reset();
|
set_safe_mode(wait_for_safe_mode_reset());
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_init();
|
stack_init();
|
||||||
|
@ -956,8 +982,8 @@ int __attribute__((used)) main(void) {
|
||||||
|
|
||||||
// Check whether CIRCUITPY is available. No need to reset to get safe mode
|
// Check whether CIRCUITPY is available. No need to reset to get safe mode
|
||||||
// since we haven't run user code yet.
|
// since we haven't run user code yet.
|
||||||
if (!filesystem_init(safe_mode == NO_SAFE_MODE, false)) {
|
if (!filesystem_init(get_safe_mode() == SAFE_MODE_NONE, false)) {
|
||||||
safe_mode = NO_CIRCUITPY;
|
set_safe_mode(SAFE_MODE_NO_CIRCUITPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CIRCUITPY_ALARM
|
#if CIRCUITPY_ALARM
|
||||||
|
@ -982,16 +1008,23 @@ int __attribute__((used)) main(void) {
|
||||||
supervisor_set_run_reason(RUN_REASON_STARTUP);
|
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 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();
|
autoreload_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default our internal flash is readonly to local python code and
|
// 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_concurrent_write_protection(true);
|
||||||
filesystem_set_internal_writable_by_usb(CIRCUITPY_USB == 1);
|
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();
|
supervisor_workflow_start();
|
||||||
|
|
||||||
|
@ -1016,7 +1049,7 @@ int __attribute__((used)) main(void) {
|
||||||
// If code.py did a fake deep sleep, pretend that we
|
// If code.py did a fake deep sleep, pretend that we
|
||||||
// are running code.py for the first time after a hard
|
// are running code.py for the first time after a hard
|
||||||
// reset. This will preserve any alarm information.
|
// 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 {
|
} else {
|
||||||
skip_repl = false;
|
skip_repl = false;
|
||||||
}
|
}
|
||||||
|
@ -1076,14 +1109,14 @@ void gc_collect(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NORETURN nlr_jump_fail(void *val) {
|
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) {
|
while (true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
static void NORETURN __fatal_error(const char *msg) {
|
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) {
|
while (true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#define CALIBRATE_CRYSTALLESS 1
|
#define CALIBRATE_CRYSTALLESS 1
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode.
|
// 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
|
// Increase stack size slightly due to CPX library import nesting
|
||||||
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#define CALIBRATE_CRYSTALLESS 1
|
#define CALIBRATE_CRYSTALLESS 1
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode.
|
// 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
|
// Increase stack size slightly due to CPX library import nesting
|
||||||
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#define CALIBRATE_CRYSTALLESS 1
|
#define CALIBRATE_CRYSTALLESS 1
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode.
|
// 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.
|
// Increase stack size slightly due to CPX library import nesting.
|
||||||
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
#define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#define CALIBRATE_CRYSTALLESS 1
|
#define CALIBRATE_CRYSTALLESS 1
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode.
|
// 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_SCL (&pin_PA01)
|
||||||
#define DEFAULT_I2C_BUS_SDA (&pin_PA00)
|
#define DEFAULT_I2C_BUS_SDA (&pin_PA00)
|
||||||
|
|
|
@ -53,3 +53,13 @@ CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf
|
||||||
|
|
||||||
# Override optimization to keep binary small
|
# Override optimization to keep binary small
|
||||||
OPTIMIZATION_FLAGS = -Os
|
OPTIMIZATION_FLAGS = -Os
|
||||||
|
|
||||||
|
# We don't have room for the fonts for terminalio for certain languages,
|
||||||
|
# so turn off terminalio, and if it's off and displayio is on,
|
||||||
|
# force a clean build.
|
||||||
|
# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an
|
||||||
|
# ifeq, because it's not set yet.
|
||||||
|
ifneq (,$(filter $(TRANSLATION),ja ko ru))
|
||||||
|
CIRCUITPY_TERMINALIO = 0
|
||||||
|
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
|
||||||
|
endif
|
||||||
|
|
|
@ -51,9 +51,8 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables.
|
||||||
// "HardFault".
|
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
HardFault_Handler();
|
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
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;
|
_bootloader_dbl_tap = DBL_TAP_MAGIC_QUICK_BOOT;
|
||||||
}
|
}
|
||||||
if (runmode == RUNMODE_SAFE_MODE) {
|
if (runmode == RUNMODE_SAFE_MODE) {
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ CIRCUITPY_ZLIB = 0
|
||||||
|
|
||||||
ifeq ($(INTERNAL_FLASH_FILESYSTEM),1)
|
ifeq ($(INTERNAL_FLASH_FILESYSTEM),1)
|
||||||
CIRCUITPY_ONEWIREIO ?= 0
|
CIRCUITPY_ONEWIREIO ?= 0
|
||||||
|
CIRCUITPY_SAFEMODE_PY ?= 0
|
||||||
CIRCUITPY_USB_IDENTIFICATION ?= 0
|
CIRCUITPY_USB_IDENTIFICATION ?= 0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -77,10 +78,8 @@ SUPEROPT_VM = 0
|
||||||
|
|
||||||
CIRCUITPY_LTO_PARTITION = one
|
CIRCUITPY_LTO_PARTITION = one
|
||||||
|
|
||||||
ifeq ($(CIRCUITPY_FULL_BUILD),0)
|
# On smaller builds this saves about 180 bytes. On other boards, it may -increase- space used, so use with care.
|
||||||
# On the smallest boards, this saves about 180 bytes. On other boards, it may -increase- space used.
|
|
||||||
CFLAGS_BOARD = -fweb -frename-registers
|
CFLAGS_BOARD = -fweb -frename-registers
|
||||||
endif
|
|
||||||
|
|
||||||
endif # samd21
|
endif # samd21
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
@ -368,20 +368,20 @@ safe_mode_t port_init(void) {
|
||||||
|
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) {
|
if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) {
|
||||||
return BROWNOUT;
|
return SAFE_MODE_BROWNOUT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
if (RSTC->RCAUSE.bit.BODVDD == 1 || RSTC->RCAUSE.bit.BODCORE == 1) {
|
if (RSTC->RCAUSE.bit.BODVDD == 1 || RSTC->RCAUSE.bit.BODCORE == 1) {
|
||||||
return BROWNOUT;
|
return SAFE_MODE_BROWNOUT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (board_requests_safe_mode()) {
|
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) {
|
void reset_port(void) {
|
||||||
|
@ -720,7 +720,7 @@ __attribute__((used)) void HardFault_Handler(void) {
|
||||||
REG_MTB_MASTER = 0x00000000 + 6;
|
REG_MTB_MASTER = 0x00000000 + 6;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
reset_into_safe_mode(HARD_CRASH);
|
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||||
while (true) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// reset_into_safe_mode(LOCKING_ERROR);
|
// reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
if (nesting_count > 0) {
|
||||||
|
|
|
@ -78,10 +78,10 @@ safe_mode_t port_init(void) {
|
||||||
// Check brownout.
|
// Check brownout.
|
||||||
|
|
||||||
if (board_requests_safe_mode()) {
|
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) {
|
void reset_port(void) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
if (runmode == RUNMODE_BOOTLOADER) {
|
if (runmode == RUNMODE_BOOTLOADER) {
|
||||||
mp_raise_ValueError(translate("Cannot reset into bootloader because no bootloader is present"));
|
mp_raise_ValueError(translate("Cannot reset into bootloader because no bootloader is present"));
|
||||||
} else if (runmode == RUNMODE_SAFE_MODE) {
|
} else if (runmode == RUNMODE_SAFE_MODE) {
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,10 @@ safe_mode_t port_init(void) {
|
||||||
heap_size = size / sizeof(uint32_t);
|
heap_size = size / sizeof(uint32_t);
|
||||||
|
|
||||||
if (board_requests_safe_mode()) {
|
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) {
|
void reset_cpu(void) {
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO38)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO38)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO37)
|
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO37)
|
||||||
|
|
||||||
// Explanation of how a user got into safe mode
|
// 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
|
// UART pins attached to the USB-serial converter chip
|
||||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1)
|
||||||
|
|
|
@ -108,7 +108,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
break;
|
break;
|
||||||
case RUNMODE_SAFE_MODE:
|
case RUNMODE_SAFE_MODE:
|
||||||
// enter safe mode on next boot
|
// enter safe mode on next boot
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
break;
|
break;
|
||||||
case RUNMODE_BOOTLOADER:
|
case RUNMODE_BOOTLOADER:
|
||||||
// DFU download
|
// DFU download
|
||||||
|
|
|
@ -318,25 +318,25 @@ safe_mode_t port_init(void) {
|
||||||
}
|
}
|
||||||
if (heap == NULL) {
|
if (heap == NULL) {
|
||||||
heap_size = 0;
|
heap_size = 0;
|
||||||
return NO_HEAP;
|
return SAFE_MODE_NO_HEAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_reset_reason_t reason = esp_reset_reason();
|
esp_reset_reason_t reason = esp_reset_reason();
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case ESP_RST_BROWNOUT:
|
case ESP_RST_BROWNOUT:
|
||||||
return BROWNOUT;
|
return SAFE_MODE_BROWNOUT;
|
||||||
case ESP_RST_PANIC:
|
case ESP_RST_PANIC:
|
||||||
return HARD_CRASH;
|
return SAFE_MODE_HARD_FAULT;
|
||||||
case ESP_RST_INT_WDT:
|
case ESP_RST_INT_WDT:
|
||||||
// The interrupt watchdog is used internally to make sure that latency sensitive
|
// 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.
|
// interrupt code isn't blocked. User watchdog resets come through ESP_RST_WDT.
|
||||||
return WATCHDOG_RESET;
|
return SAFE_MODE_WATCHDOG;
|
||||||
case ESP_RST_WDT:
|
case ESP_RST_WDT:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_port(void) {
|
void reset_port(void) {
|
||||||
|
|
|
@ -70,9 +70,8 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
__attribute__((section(".ramtext")))
|
__attribute__((section(".ramtext")))
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables.
|
||||||
// "HardFault".
|
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
asm ("ebreak");
|
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
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) {
|
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
if (runmode == RUNMODE_SAFE_MODE) {
|
if (runmode == RUNMODE_SAFE_MODE) {
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ safe_mode_t port_init(void) {
|
||||||
irq_setmask(0);
|
irq_setmask(0);
|
||||||
irq_setie(1);
|
irq_setie(1);
|
||||||
tick_init();
|
tick_init();
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint32_t _ebss;
|
extern uint32_t _ebss;
|
||||||
|
|
|
@ -52,12 +52,10 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
nesting_count++;
|
nesting_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardFault_Handler(void);
|
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables
|
||||||
// "HardFault".
|
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
HardFault_Handler();
|
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
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;
|
DBL_TAP_REG = DBL_TAP_MAGIC_QUICK_BOOT;
|
||||||
}
|
}
|
||||||
if (runmode == RUNMODE_SAFE_MODE) {
|
if (runmode == RUNMODE_SAFE_MODE) {
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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`.
|
// run yet, which uses `never_reset` to protect critical pins from being reset by `reset_port`.
|
||||||
|
|
||||||
if (board_requests_safe_mode()) {
|
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) {
|
void reset_port(void) {
|
||||||
|
@ -419,7 +419,7 @@ void port_idle_until_interrupt(void) {
|
||||||
*/
|
*/
|
||||||
void MemManage_Handler(void);
|
void MemManage_Handler(void);
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,7 @@ __attribute__((used)) void MemManage_Handler(void) {
|
||||||
*/
|
*/
|
||||||
void BusFault_Handler(void);
|
void BusFault_Handler(void);
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
@ -441,7 +441,7 @@ __attribute__((used)) void BusFault_Handler(void) {
|
||||||
*/
|
*/
|
||||||
void UsageFault_Handler(void);
|
void UsageFault_Handler(void);
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
@ -452,7 +452,7 @@ __attribute__((used)) void UsageFault_Handler(void) {
|
||||||
*/
|
*/
|
||||||
void HardFault_Handler(void);
|
void HardFault_Handler(void);
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
#define CIRCUITPY_BOOT_BUTTON (&pin_P0_29)
|
#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)
|
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
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];
|
bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];
|
||||||
|
|
|
@ -68,9 +68,8 @@ void common_hal_mcu_disable_interrupts() {
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts() {
|
void common_hal_mcu_enable_interrupts() {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables.
|
||||||
// crash.
|
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
reset_into_safe_mode(HARD_CRASH);
|
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
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);
|
sd_power_gpregret_set(0,0);
|
||||||
}
|
}
|
||||||
if (runmode == RUNMODE_SAFE_MODE) {
|
if (runmode == RUNMODE_SAFE_MODE) {
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ void port_internal_flash_flush(void) {
|
||||||
// Skip if data is the same
|
// Skip if data is the same
|
||||||
if (memcmp(_flash_cache, (void *)_flash_page_addr, FLASH_PAGE_SIZE) != 0) {
|
if (memcmp(_flash_cache, (void *)_flash_page_addr, FLASH_PAGE_SIZE) != 0) {
|
||||||
if (!nrf_nvm_safe_flash_page_write(_flash_page_addr, _flash_cache)) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ extern void qspi_disable(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void power_warning_handler(void) {
|
static void power_warning_handler(void) {
|
||||||
reset_into_safe_mode(BROWNOUT);
|
reset_into_safe_mode(SAFE_MODE_BROWNOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t reset_reason_saved = 0;
|
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`,
|
// If USB is connected, then the user might be editing `code.py`,
|
||||||
// in which case we should reboot into Safe Mode.
|
// in which case we should reboot into Safe Mode.
|
||||||
if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) {
|
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) {
|
void reset_port(void) {
|
||||||
|
@ -399,7 +399,7 @@ void port_idle_until_interrupt(void) {
|
||||||
|
|
||||||
extern void HardFault_Handler(void);
|
extern void HardFault_Handler(void);
|
||||||
void HardFault_Handler(void) {
|
void HardFault_Handler(void) {
|
||||||
reset_into_safe_mode(HARD_CRASH);
|
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||||
while (true) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// reset_into_safe_mode(LOCKING_ERROR);
|
// reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
if (nesting_count > 0) {
|
||||||
|
@ -79,7 +79,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
next_reset_to_bootloader = true;
|
next_reset_to_bootloader = true;
|
||||||
break;
|
break;
|
||||||
case RUNMODE_SAFE_MODE:
|
case RUNMODE_SAFE_MODE:
|
||||||
safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE);
|
safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -161,10 +161,10 @@ safe_mode_t port_init(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (board_requests_safe_mode()) {
|
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) {
|
void reset_port(void) {
|
||||||
|
@ -312,7 +312,7 @@ __attribute__((used)) void HardFault_Handler(void) {
|
||||||
REG_MTB_MASTER = 0x00000000 + 6;
|
REG_MTB_MASTER = 0x00000000 + 6;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
reset_into_safe_mode(HARD_CRASH);
|
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||||
while (true) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,7 @@ STATIC int next_filter(canio_can_obj_t *can) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset_into_safe_mode(MICROPY_FATAL_ERROR);
|
mp_raise_msg_varg(&mp_type_RuntimeError, translate("%q"), MP_QSTR_Listener);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDE = "extended ID" flag of packet header. We always add this bit to the
|
// IDE = "extended ID" flag of packet header. We always add this bit to the
|
||||||
|
|
|
@ -61,9 +61,8 @@ void common_hal_mcu_disable_interrupts(void) {
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts(void) {
|
void common_hal_mcu_enable_interrupts(void) {
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables.
|
||||||
// "HardFault".
|
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||||
asm ("bkpt");
|
|
||||||
}
|
}
|
||||||
nesting_count--;
|
nesting_count--;
|
||||||
if (nesting_count > 0) {
|
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) {
|
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
if (runmode == RUNMODE_SAFE_MODE) {
|
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) {
|
if (runmode == RUNMODE_BOOTLOADER) {
|
||||||
next_reset_to_bootloader = true;
|
next_reset_to_bootloader = true;
|
||||||
|
|
|
@ -215,7 +215,7 @@ void port_internal_flash_flush(void) {
|
||||||
EraseInitStruct.NbSectors = 1;
|
EraseInitStruct.NbSectors = 1;
|
||||||
#endif
|
#endif
|
||||||
if (sector_size > sizeof(_flash_cache) || sector_start_addr == 0xffffffff) {
|
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
|
// Skip if data is the same
|
||||||
|
@ -228,7 +228,7 @@ void port_internal_flash_flush(void) {
|
||||||
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
|
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
|
||||||
// error occurred during sector erase
|
// error occurred during sector erase
|
||||||
HAL_FLASH_Lock(); // lock the flash
|
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;
|
uint32_t *cache_addr = (uint32_t *)_flash_cache;
|
||||||
|
@ -240,7 +240,7 @@ void port_internal_flash_flush(void) {
|
||||||
(uint32_t)cache_addr) != HAL_OK) {
|
(uint32_t)cache_addr) != HAL_OK) {
|
||||||
// error occurred during flash write
|
// error occurred during flash write
|
||||||
HAL_FLASH_Lock(); // lock the flash
|
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
|
// RAM memory is by word (4 byte), but flash memory is by byte
|
||||||
cache_addr += 8;
|
cache_addr += 8;
|
||||||
|
@ -253,7 +253,7 @@ void port_internal_flash_flush(void) {
|
||||||
*(uint64_t *)cache_addr) != HAL_OK) {
|
*(uint64_t *)cache_addr) != HAL_OK) {
|
||||||
// error occurred during flash write
|
// error occurred during flash write
|
||||||
HAL_FLASH_Lock(); // lock the flash
|
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
|
// RAM memory is by word (4 byte), but flash memory is by byte
|
||||||
cache_addr += 2;
|
cache_addr += 2;
|
||||||
|
@ -267,7 +267,7 @@ void port_internal_flash_flush(void) {
|
||||||
(uint64_t)*cache_addr) != HAL_OK) {
|
(uint64_t)*cache_addr) != HAL_OK) {
|
||||||
// error occurred during flash write
|
// error occurred during flash write
|
||||||
HAL_FLASH_Lock(); // lock the flash
|
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
|
// RAM memory is by word (4 byte), but flash memory is by byte
|
||||||
cache_addr += 1;
|
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
|
// Fail for any sector outside what's supported by the cache
|
||||||
if (sector_size > sizeof(_flash_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
|
// Find how many blocks are left in the sector
|
||||||
|
|
|
@ -211,7 +211,7 @@ safe_mode_t port_init(void) {
|
||||||
// Turn off SysTick
|
// Turn off SysTick
|
||||||
SysTick->CTRL = 0;
|
SysTick->CTRL = 0;
|
||||||
|
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_Delay(uint32_t delay_ms) {
|
void HAL_Delay(uint32_t delay_ms) {
|
||||||
|
@ -357,28 +357,28 @@ uint32_t port_get_saved_word(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((used)) 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) {
|
while (true) {
|
||||||
asm ("nop;");
|
asm ("nop;");
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,6 +530,11 @@ $(filter $(SRC_PATTERNS), \
|
||||||
wifi/Packet.c \
|
wifi/Packet.c \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ifeq ($(CIRCUITPY_SAFEMODE_PY),1)
|
||||||
|
SRC_BINDINGS_ENUMS += \
|
||||||
|
supervisor/SafeModeReason.c
|
||||||
|
endif
|
||||||
|
|
||||||
SRC_BINDINGS_ENUMS += \
|
SRC_BINDINGS_ENUMS += \
|
||||||
util.c
|
util.c
|
||||||
|
|
||||||
|
|
|
@ -372,6 +372,10 @@ CFLAGS += -DCIRCUITPY_ROTARYIO_SOFTENCODER=$(CIRCUITPY_ROTARYIO_SOFTENCODER)
|
||||||
CIRCUITPY_RTC ?= 1
|
CIRCUITPY_RTC ?= 1
|
||||||
CFLAGS += -DCIRCUITPY_RTC=$(CIRCUITPY_RTC)
|
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.
|
# CIRCUITPY_SAMD is handled in the atmel-samd tree.
|
||||||
# Only for SAMD chips.
|
# Only for SAMD chips.
|
||||||
# Assume not a SAMD build.
|
# Assume not a SAMD build.
|
||||||
|
|
4
py/gc.c
4
py/gc.c
|
@ -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) {
|
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();
|
GC_ENTER();
|
||||||
|
@ -712,7 +712,7 @@ void gc_free(void *ptr) {
|
||||||
GC_EXIT();
|
GC_EXIT();
|
||||||
} else {
|
} else {
|
||||||
if (MP_STATE_MEM(gc_pool_start) == 0) {
|
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
|
// get the GC block number corresponding to this pointer
|
||||||
assert(VERIFY_PTR(ptr));
|
assert(VERIFY_PTR(ptr));
|
||||||
|
|
|
@ -42,7 +42,7 @@ MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_
|
||||||
//| """The reason the microntroller was last reset"""
|
//| """The reason the microntroller was last reset"""
|
||||||
//|
|
//|
|
||||||
//| POWER_ON: object
|
//| POWER_ON: object
|
||||||
//| """The microntroller was started from power off."""
|
//| """The microcontroller was started from power off."""
|
||||||
//|
|
//|
|
||||||
//| BROWNOUT: object
|
//| BROWNOUT: object
|
||||||
//| """The microntroller was reset due to too low a voltage."""
|
//| """The microntroller was reset due to too low a voltage."""
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "shared-bindings/supervisor/RunReason.h"
|
#include "shared-bindings/supervisor/RunReason.h"
|
||||||
#include "shared-bindings/supervisor/Runtime.h"
|
#include "shared-bindings/supervisor/Runtime.h"
|
||||||
|
#include "shared-bindings/supervisor/SafeModeReason.h"
|
||||||
|
|
||||||
#include "supervisor/shared/reload.h"
|
#include "supervisor/shared/reload.h"
|
||||||
#include "supervisor/shared/stack.h"
|
#include "supervisor/shared/stack.h"
|
||||||
|
@ -106,7 +107,7 @@ void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//| run_reason: RunReason
|
//| 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) {
|
STATIC mp_obj_t supervisor_runtime_get_run_reason(mp_obj_t self) {
|
||||||
return cp_enum_find(&supervisor_run_reason_type, _run_reason);
|
return cp_enum_find(&supervisor_run_reason_type, _run_reason);
|
||||||
}
|
}
|
||||||
|
@ -115,6 +116,23 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_run_reason_obj, supervisor_runt
|
||||||
MP_PROPERTY_GETTER(supervisor_runtime_run_reason_obj,
|
MP_PROPERTY_GETTER(supervisor_runtime_run_reason_obj,
|
||||||
(mp_obj_t)&supervisor_runtime_get_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).
|
||||||
|
//|
|
||||||
|
//| **Limitations**: Raises ``NotImplementedError`` on builds that do not implement ``safemode.py``.
|
||||||
|
//| """
|
||||||
|
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
|
//| autoreload: bool
|
||||||
//| """Whether CircuitPython may autoreload based on workflow writes to the filesystem."""
|
//| """Whether CircuitPython may autoreload based on workflow writes to the filesystem."""
|
||||||
//|
|
//|
|
||||||
|
@ -218,6 +236,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_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_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_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_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_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) },
|
{ MP_ROM_QSTR(MP_QSTR_next_stack_limit), MP_ROM_PTR(&supervisor_runtime_next_stack_limit_obj) },
|
||||||
|
|
|
@ -31,12 +31,16 @@
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
|
||||||
#include "shared-bindings/supervisor/RunReason.h"
|
#include "shared-bindings/supervisor/RunReason.h"
|
||||||
|
#include "shared-bindings/supervisor/SafeModeReason.h"
|
||||||
|
|
||||||
extern const mp_obj_type_t supervisor_runtime_type;
|
extern const mp_obj_type_t supervisor_runtime_type;
|
||||||
|
|
||||||
supervisor_run_reason_t supervisor_get_run_reason(void);
|
supervisor_run_reason_t supervisor_get_run_reason(void);
|
||||||
void supervisor_set_run_reason(supervisor_run_reason_t run_reason);
|
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_connected(void);
|
||||||
|
|
||||||
bool common_hal_supervisor_runtime_get_serial_bytes_available(void);
|
bool common_hal_supervisor_runtime_get_serial_bytes_available(void);
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
//| class SafeModeReason:
|
||||||
|
//| """The reason that CircuitPython went into safe mode.
|
||||||
|
//|
|
||||||
|
//| **Limitations**: Class not available on builds that do not implement ``safemode.py``.
|
||||||
|
//| """
|
||||||
|
//|
|
||||||
|
MAKE_ENUM_MAP(supervisor_safe_mode_reason) {
|
||||||
|
|
||||||
|
//| 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.
|
||||||
|
//| This safe mode does **not** cause ``safemode.py`` to be run, since its purpose
|
||||||
|
//| is to prevent all user code from running.
|
||||||
|
//| This allows errors in ``safemode.py`` to be corrected easily.
|
||||||
|
//| """
|
||||||
|
//|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
|
@ -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;
|
|
@ -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_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_reload), MP_ROM_PTR(&supervisor_reload_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_RunReason), MP_ROM_PTR(&supervisor_run_reason_type) },
|
{ 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_ROM_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_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_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) },
|
{ MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },
|
||||||
|
|
|
@ -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
|
|
|
@ -43,20 +43,28 @@
|
||||||
#define SAFE_MODE_DATA_GUARD 0xad0000af
|
#define SAFE_MODE_DATA_GUARD 0xad0000af
|
||||||
#define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff
|
#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) {
|
safe_mode_t wait_for_safe_mode_reset(void) {
|
||||||
uint32_t reset_state = port_get_saved_word();
|
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) {
|
if ((reset_state & SAFE_MODE_DATA_GUARD_MASK) == SAFE_MODE_DATA_GUARD) {
|
||||||
safe_mode = (reset_state & ~SAFE_MODE_DATA_GUARD_MASK) >> 8;
|
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);
|
port_set_saved_word(SAFE_MODE_DATA_GUARD);
|
||||||
current_safe_mode = safe_mode;
|
_safe_mode = safe_mode;
|
||||||
return safe_mode;
|
return safe_mode;
|
||||||
} else {
|
} else {
|
||||||
current_safe_mode = 0;
|
_safe_mode = SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason();
|
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_RESET_PIN &&
|
||||||
reset_reason != RESET_REASON_UNKNOWN &&
|
reset_reason != RESET_REASON_UNKNOWN &&
|
||||||
reset_reason != RESET_REASON_SOFTWARE) {
|
reset_reason != RESET_REASON_SOFTWARE) {
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
#if CIRCUITPY_SKIP_SAFE_MODE_WAIT
|
#if CIRCUITPY_SKIP_SAFE_MODE_WAIT
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
#endif
|
#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.
|
// Wait for a while to allow for reset.
|
||||||
|
|
||||||
#if CIRCUITPY_STATUS_LED
|
#if CIRCUITPY_STATUS_LED
|
||||||
|
@ -106,11 +114,11 @@ safe_mode_t wait_for_safe_mode_reset(void) {
|
||||||
status_led_deinit();
|
status_led_deinit();
|
||||||
#endif
|
#endif
|
||||||
if (boot_in_safe_mode) {
|
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.
|
// Restore the original state of the saved word if no reset occured during our wait period.
|
||||||
port_set_saved_word(reset_state);
|
port_set_saved_word(reset_state);
|
||||||
return NO_SAFE_MODE;
|
return SAFE_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void safe_mode_on_next_reset(safe_mode_t reason) {
|
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.
|
// 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) {
|
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) {
|
while (true) {
|
||||||
// This very bad because it means running in safe mode didn't save us. Only ignore brownout
|
// 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.
|
// because it may be due to a switch bouncing.
|
||||||
|
@ -133,105 +141,95 @@ void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) {
|
||||||
|
|
||||||
|
|
||||||
void print_safe_mode_message(safe_mode_t reason) {
|
void print_safe_mode_message(safe_mode_t reason) {
|
||||||
if (reason == NO_SAFE_MODE) {
|
if (reason == SAFE_MODE_NONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_write("\r\n");
|
serial_write_compressed(translate("\nYou are in safe mode because:\n"));
|
||||||
serial_write_compressed(translate("You are in safe mode because:\n"));
|
|
||||||
|
|
||||||
const compressed_string_t *message = NULL;
|
const compressed_string_t *message = NULL;
|
||||||
|
|
||||||
// First check for safe mode reasons that do not necessarily reflect bugs.
|
// First check for safe mode reasons that do not necessarily reflect bugs.
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case USER_SAFE_MODE:
|
case SAFE_MODE_BROWNOUT:
|
||||||
|
message = translate("The power dipped. Make sure you are providing enough power.");
|
||||||
|
break;
|
||||||
|
case SAFE_MODE_USER:
|
||||||
#if defined(BOARD_USER_SAFE_MODE_ACTION)
|
#if defined(BOARD_USER_SAFE_MODE_ACTION)
|
||||||
message = BOARD_USER_SAFE_MODE_ACTION;
|
message = BOARD_USER_SAFE_MODE_ACTION;
|
||||||
#elif defined(CIRCUITPY_BOOT_BUTTON)
|
#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");
|
||||||
#endif
|
#else
|
||||||
#if defined(BOARD_USER_SAFE_MODE_ACTION) || defined(CIRCUITPY_BOOT_BUTTON)
|
message = translate("You pressed the reset button during boot.");
|
||||||
// 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.");
|
|
||||||
// The final piece is printed below.
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case MANUAL_SAFE_MODE:
|
case SAFE_MODE_NO_CIRCUITPY:
|
||||||
message = translate("You pressed the reset button during boot. Press again to exit safe mode.");
|
message = translate("CIRCUITPY drive could not be found or created.");
|
||||||
break;
|
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.");
|
message = translate("The `microcontroller` module was used to boot into safe mode.");
|
||||||
break;
|
break;
|
||||||
case BROWNOUT:
|
#if CIRCUITPY_SAFEMODE_PY
|
||||||
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;
|
break;
|
||||||
case USB_TOO_MANY_ENDPOINTS:
|
#endif
|
||||||
|
case SAFE_MODE_STACK_OVERFLOW:
|
||||||
|
message = translate("Heap was corrupted because the stack was too small. Increase stack size.");
|
||||||
|
break;
|
||||||
|
case SAFE_MODE_USB_TOO_MANY_ENDPOINTS:
|
||||||
message = translate("USB devices need more endpoints than are available.");
|
message = translate("USB devices need more endpoints than are available.");
|
||||||
break;
|
break;
|
||||||
case USB_TOO_MANY_INTERFACE_NAMES:
|
case SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES:
|
||||||
message = translate("USB devices specify too many interface names.");
|
message = translate("USB devices specify too many interface names.");
|
||||||
break;
|
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).");
|
message = translate("Boot device must be first (interface #0).");
|
||||||
break;
|
break;
|
||||||
case WATCHDOG_RESET:
|
case SAFE_MODE_WATCHDOG:
|
||||||
message = translate("Internal watchdog timer expired.");
|
message = translate("Internal watchdog timer expired.");
|
||||||
break;
|
break;
|
||||||
case NO_CIRCUITPY:
|
|
||||||
message = translate("CIRCUITPY drive could not be found or created.");
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
|
// Non-crash safe mode.
|
||||||
serial_write_compressed(message);
|
serial_write_compressed(message);
|
||||||
serial_write("\r\n");
|
} else {
|
||||||
return;
|
// Something worse happened.
|
||||||
|
serial_write_compressed(translate("CircuitPython core code crashed hard. Whoops!\n"));
|
||||||
|
switch (reason) {
|
||||||
|
case SAFE_MODE_GC_ALLOC_OUTSIDE_VM:
|
||||||
|
message = translate("Heap allocation when VM not running.");
|
||||||
|
break;
|
||||||
|
case SAFE_MODE_FLASH_WRITE_FAIL:
|
||||||
|
message = translate("Failed to write internal flash.");
|
||||||
|
break;
|
||||||
|
case SAFE_MODE_HARD_FAULT:
|
||||||
|
message = translate("Fault detected by hardware.");
|
||||||
|
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("Unable to allocate the heap.");
|
||||||
|
break;
|
||||||
|
case SAFE_MODE_SDK_FATAL_ERROR:
|
||||||
|
message = translate("Third-party firmware fatal error.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = translate("Unknown reason.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
serial_write_compressed(message);
|
||||||
|
serial_write_compressed(translate("\nPlease file an issue with your program at https://github.com/adafruit/circuitpython/issues."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something worse happened.
|
// Always tell user how to get out of safe mode.
|
||||||
|
serial_write_compressed(translate("\nPress reset to exit safe mode.\n"));
|
||||||
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:
|
|
||||||
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:
|
|
||||||
message = translate("Failed to write internal flash.");
|
|
||||||
break;
|
|
||||||
case MEM_MANAGE:
|
|
||||||
message = translate("Invalid memory access.");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
message = translate("Unknown reason.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
serial_write_compressed(message);
|
|
||||||
serial_write_compressed(translate("\nPlease file an issue with the contents of your CIRCUITPY drive at \nhttps://github.com/adafruit/circuitpython/issues\n"));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,27 +30,32 @@
|
||||||
#include "py/mpconfig.h"
|
#include "py/mpconfig.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NO_SAFE_MODE = 0,
|
SAFE_MODE_NONE = 0,
|
||||||
BROWNOUT,
|
// BROWNOUT should be lowest after SAFE_MODE_NONE.
|
||||||
HARD_CRASH,
|
SAFE_MODE_BROWNOUT,
|
||||||
USER_SAFE_MODE,
|
// alphabetical from here down
|
||||||
HEAP_OVERWRITTEN,
|
SAFE_MODE_FLASH_WRITE_FAIL,
|
||||||
MANUAL_SAFE_MODE,
|
SAFE_MODE_GC_ALLOC_OUTSIDE_VM,
|
||||||
MICROPY_NLR_JUMP_FAIL,
|
SAFE_MODE_HARD_FAULT,
|
||||||
MICROPY_FATAL_ERROR,
|
SAFE_MODE_INTERRUPT_ERROR,
|
||||||
GC_ALLOC_OUTSIDE_VM,
|
SAFE_MODE_MANUAL,
|
||||||
PROGRAMMATIC_SAFE_MODE,
|
SAFE_MODE_NLR_JUMP_FAIL,
|
||||||
NORDIC_SOFT_DEVICE_ASSERT,
|
SAFE_MODE_NO_CIRCUITPY,
|
||||||
FLASH_WRITE_FAIL,
|
SAFE_MODE_NO_HEAP,
|
||||||
MEM_MANAGE,
|
SAFE_MODE_PROGRAMMATIC,
|
||||||
WATCHDOG_RESET,
|
SAFE_MODE_SAFEMODE_PY_ERROR,
|
||||||
USB_TOO_MANY_ENDPOINTS,
|
SAFE_MODE_SDK_FATAL_ERROR,
|
||||||
USB_TOO_MANY_INTERFACE_NAMES,
|
SAFE_MODE_STACK_OVERFLOW,
|
||||||
USB_BOOT_DEVICE_NOT_INTERFACE_ZERO,
|
SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO,
|
||||||
NO_HEAP,
|
SAFE_MODE_USB_TOO_MANY_ENDPOINTS,
|
||||||
NO_CIRCUITPY,
|
SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES,
|
||||||
|
SAFE_MODE_USER,
|
||||||
|
SAFE_MODE_WATCHDOG,
|
||||||
} safe_mode_t;
|
} 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);
|
safe_mode_t wait_for_safe_mode_reset(void);
|
||||||
|
|
||||||
void safe_mode_on_next_reset(safe_mode_t reason);
|
void safe_mode_on_next_reset(safe_mode_t reason);
|
||||||
|
|
|
@ -74,7 +74,7 @@ inline bool stack_ok(void) {
|
||||||
|
|
||||||
inline void assert_heap_ok(void) {
|
inline void assert_heap_ok(void) {
|
||||||
if (!stack_ok()) {
|
if (!stack_ok()) {
|
||||||
reset_into_safe_mode(HEAP_OVERWRITTEN);
|
reset_into_safe_mode(SAFE_MODE_STACK_OVERFLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ static void usb_build_configuration_descriptor(void) {
|
||||||
if (usb_hid_boot_device() > 0 && descriptor_counts.current_interface > 0) {
|
if (usb_hid_boot_device() > 0 && descriptor_counts.current_interface > 0) {
|
||||||
// Hosts using boot devices generally to expect them to be at interface zero,
|
// Hosts using boot devices generally to expect them to be at interface zero,
|
||||||
// and will not work properly otherwise.
|
// 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 += usb_hid_add_descriptor(
|
||||||
descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string,
|
descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string,
|
||||||
|
@ -258,14 +258,14 @@ static void usb_build_configuration_descriptor(void) {
|
||||||
if (descriptor_counts.current_endpoint > USB_NUM_ENDPOINT_PAIRS ||
|
if (descriptor_counts.current_endpoint > USB_NUM_ENDPOINT_PAIRS ||
|
||||||
descriptor_counts.num_in_endpoints > USB_NUM_IN_ENDPOINTS ||
|
descriptor_counts.num_in_endpoints > USB_NUM_IN_ENDPOINTS ||
|
||||||
descriptor_counts.num_out_endpoints > USB_NUM_OUT_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.
|
// str must not be on the heap.
|
||||||
void usb_add_interface_string(uint8_t interface_string_index, const char str[]) {
|
void usb_add_interface_string(uint8_t interface_string_index, const char str[]) {
|
||||||
if (interface_string_index > MAX_INTERFACE_STRINGS) {
|
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;
|
collected_interface_strings[interface_string_index].char_str = str;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
safe_mode_t wait_for_safe_mode_reset(void) {
|
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) {
|
void reset_into_safe_mode(safe_mode_t reason) {
|
||||||
|
|
Loading…
Reference in New Issue