diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 3503e5b194..5db7c04686 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -1,6 +1,14 @@ name: Fetch external deps inputs: + action: + required: false + default: restore + type: choice + options: + - cache + - restore + platform: required: false default: none @@ -78,7 +86,7 @@ runs: if: inputs.platform != 'esp' uses: ./.github/actions/deps/python with: - action: ${{ fromJSON('["restore", "cache"]')[github.job == 'scheduler'] }} + action: ${{ inputs.action }} - name: Install python dependencies run: pip install -r requirements-dev.txt shell: bash diff --git a/.github/actions/upload_aws/action.yml b/.github/actions/upload_aws/action.yml index 7aee8c7e78..643dd00342 100644 --- a/.github/actions/upload_aws/action.yml +++ b/.github/actions/upload_aws/action.yml @@ -24,7 +24,8 @@ runs: (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) run: >- [ -z "$AWS_ACCESS_KEY_ID" ] || - aws s3 cp ${{ inputs.source }} s3://adafruit-circuit-python/bin/${{ inputs.destination }} --recursive --no-progress --region us-east-1 + aws s3 cp ${{ inputs.source }} s3://adafruit-circuit-python/bin/${{ inputs.destination }} + ${{ endsWith(inputs.source, '/') && '--recursive' || '' }} --no-progress --region us-east-1 env: AWS_PAGER: '' AWS_ACCESS_KEY_ID: ${{ inputs.AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/build-boards-custom.yml b/.github/workflows/build-boards-custom.yml new file mode 100644 index 0000000000..22ba0f62f4 --- /dev/null +++ b/.github/workflows/build-boards-custom.yml @@ -0,0 +1,104 @@ +name: Custom board build + +on: + workflow_dispatch: + inputs: + board: + description: 'Board: Found in ports/*/boards/[board_id]' + required: true + type: string + version: + description: 'Version: Can be a tag or a commit (>=8.1.0)' + required: false + default: latest + type: string + language: + description: 'Language: Found in locale/[language].po' + required: false + default: en_US + type: string + flags: + description: 'Flags: Build flags (e.g. CIRCUITPY_WIFI=1)' + required: false + type: string + debug: + description: 'Make a debug build' + required: false + default: false + type: boolean + +run-name: ${{ inputs.board }}-${{ inputs.language }}-${{ inputs.version }}${{ inputs.flags != '' && '-custom' || '' }}${{ inputs.debug && '-debug' || '' }} + +jobs: + build: + runs-on: ubuntu-22.04 + env: + PLATFORM_atmel-samd: arm + PLATFORM_broadcom: aarch + PLATFORM_cxd56: arm + PLATFORM_espressif: esp + PLATFORM_litex: riscv + PLATFORM_mimxrt10xx: arm + PLATFORM_nrf: arm + PLATFORM_raspberrypi: arm + PLATFORM_stm: arm + steps: + - name: Set up repository + run: | + git clone --filter=tree:0 https://github.com/adafruit/circuitpython.git $GITHUB_WORKSPACE + git checkout ${{ inputs.version == 'latest' && 'HEAD' || inputs.version }} + - name: Set up identifier + if: inputs.debug || inputs.flags != '' + run: | + > custom-build && git add custom-build + - name: Get port + id: get-port + run: | + PORT=$(find ports/*/boards/ -type d -name ${{ inputs.board }} | sed 's/^ports\///g;s/\/boards.*//g') + if [ -z $PORT ]; then (exit 1); else echo >> $GITHUB_OUTPUT "port=$PORT"; fi + - name: Port to platform + run: echo >> $GITHUB_ENV "PLATFORM=${{ env[format('PLATFORM_{0}', steps.get-port.outputs.port)] }}" + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Set up port + if: env.PLATFORM == 'esp' + uses: ./.github/actions/deps/ports/espressif + - name: Set up submodules + id: set-up-submodules + uses: ./.github/actions/deps/submodules + with: + action: cache + target: ${{ inputs.board }} + - name: Set up external + uses: ./.github/actions/deps/external + with: + action: cache + platform: ${{ env.PLATFORM }} + - name: Set up mpy-cross + if: steps.set-up-submodules.outputs.frozen == 'True' + uses: ./.github/actions/mpy_cross + with: + download: false + - name: Versions + run: | + tools/describe + gcc --version + python3 --version + cmake --version || true + ninja --version || true + aarch64-none-elf-gcc --version || true + arm-none-eabi-gcc --version || true + xtensa-esp32-elf-gcc --version || true + riscv32-esp-elf-gcc --version || true + riscv64-unknown-elf-gcc --version || true + mkfs.fat --version || true + - name: Build board + run: make -j2 ${{ inputs.flags }} BOARD=${{ inputs.board }} DEBUG=${{ inputs.debug && '1' || '0' }} TRANSLATION=${{ inputs.language }} + working-directory: ports/${{ steps.get-port.outputs.port }} + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.board }}-${{ inputs.language }}-${{ inputs.version }}${{ inputs.flags != '' && '-custom' || '' }}${{ inputs.debug && '-debug' || '' }} + path: ports/${{ steps.get-port.outputs.port }}/build-${{ inputs.board }}/firmware.* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6159f7291e..00c7f8749f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,6 +52,8 @@ jobs: version: true - name: Set up external uses: ./.github/actions/deps/external + with: + action: cache # Disabled: Needs to be updated # - name: Get last commit with checks # id: get-last-commit-with-checks @@ -200,16 +202,11 @@ jobs: with: name: docs path: _build/latex - - name: Zip stubs - if: >- - (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || - (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) - run: zip -9r circuitpython-stubs.zip circuitpython-stubs - name: Upload to S3 uses: ./.github/actions/upload_aws with: source: circuitpython-stubs/dist/*.tar.gz - destination: stubs/circuitpython-stubs-${{ env.CP_VERSION }}.zip + destination: stubs/circuitpython-stubs-${{ env.CP_VERSION }}.tar.gz AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Upload stubs to PyPi diff --git a/README.rst b/README.rst index d8a35fb98c..1a6dc2c33e 100644 --- a/README.rst +++ b/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 possible to fix code that causes nasty crashes by making it available through mass storage after the crash. A reset (the button) is needed after it's fixed to get back into normal mode. +- Safe mode may be handled programmatically by providing a ``safemode.py``. + ``safemode.py`` is run if the board has reset due to entering safe mode, 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. - One green flash - code completed without error. - 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 ``supervisor.disable_autoreload()``) - Autoreload is disabled while the REPL is active. -- Main is one of these: ``code.txt``, ``code.py``, ``main.py``, - ``main.txt`` -- Boot is one of these: ``boot.py``, ``boot.txt`` +- ``code.py`` may also be named``code.txt``, ``main.py``, or ``main.txt``. +- ``boot.py`` may also be named ``boot.txt``. +- ``safemode.py`` may also be named ``safemode.txt``. API ~~~ diff --git a/locale/ID.po b/locale/ID.po index 546828a14d..d4cd357358 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -2441,6 +2441,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init __() harus mengembalikan None" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 79899735de..540346161b 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -39,8 +39,20 @@ msgstr "" #: supervisor/shared/safe_mode.c msgid "" "\n" -"Please file an issue with the contents of your CIRCUITPY drive at \n" -"https://github.com/adafruit/circuitpython/issues\n" +"Please file an issue with your program at https://github.com/adafruit/" +"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 "" #: py/obj.c @@ -93,7 +105,7 @@ msgstr "" #: ports/raspberrypi/common-hal/alarm/__init__.c #: ports/raspberrypi/common-hal/analogio/AnalogOut.c #: ports/raspberrypi/common-hal/rtc/RTC.c ports/stm/common-hal/alarm/__init__.c -#: ports/stm/common-hal/rtc/RTC.c +#: ports/stm/common-hal/canio/Listener.c ports/stm/common-hal/rtc/RTC.c msgid "%q" msgstr "" @@ -538,10 +550,6 @@ msgstr "" msgid "Attempt to allocate %d blocks" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Attempted heap allocation when VM not running." -msgstr "" - #: ports/raspberrypi/audio_dma.c msgid "Audio conversion not implemented" msgstr "" @@ -590,20 +598,13 @@ msgid "Bitmap size and bits per value must match" msgstr "" #: supervisor/shared/safe_mode.c -msgid "Boot device must be first device (interface #0)." +msgid "Boot device must be first (interface #0)." msgstr "" #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "Both buttons were pressed at start up.\n" -msgstr "" - #: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c msgid "Both pins must support hardware interrupts" msgstr "" @@ -669,12 +670,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -msgid "Button A was pressed at start up.\n" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "Byte buffer must be 16 bytes." msgstr "" @@ -805,10 +800,6 @@ msgstr "" msgid "CircuitPython core code crashed hard. Whoops!\n" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython was unable to allocate the heap." -msgstr "" - #: shared-module/bitbangio/I2C.c msgid "Clock stretch too long" msgstr "" @@ -847,10 +838,6 @@ msgstr "" msgid "Couldn't allocate decoder" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Crash into the HardFault_Handler." -msgstr "" - #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -942,6 +929,10 @@ msgstr "" msgid "Error in regex" msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "" + #: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c msgid "Error: Failure to bind" msgstr "" @@ -1015,7 +1006,7 @@ msgid "Failed to write internal flash." msgstr "" #: supervisor/shared/safe_mode.c -msgid "Fatal error." +msgid "Fault detected by hardware." msgstr "" #: py/moduerrno.c @@ -1103,6 +1094,15 @@ msgstr "" msgid "Hardware in use, try alternative pins" 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 msgid "I/O operation on closed file" msgstr "" @@ -1217,6 +1217,10 @@ msgstr "" msgid "Internal watchdog timer expired." msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "" + #: py/argcheck.c shared-bindings/digitalio/DigitalInOut.c msgid "Invalid %q" msgstr "" @@ -1265,10 +1269,6 @@ msgstr "" msgid "Invalid format chunk size" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Invalid memory access." -msgstr "" - #: ports/espressif/common-hal/wifi/Radio.c msgid "Invalid multicast MAC address" msgstr "" @@ -1557,10 +1557,6 @@ msgstr "" msgid "No timer available" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Nordic system firmware failure assertion." -msgstr "" - #: ports/nrf/common-hal/_bleio/__init__.c msgid "Nordic system firmware out of memory" msgstr "" @@ -2012,53 +2008,19 @@ msgid "Temperature read timed out" msgstr "" #: supervisor/shared/safe_mode.c -msgid "The BOOT button was pressed at start up.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"The CircuitPython heap was corrupted because the stack was too small.\n" -"Increase the stack size if you know how. If not:" -msgstr "" - -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "The SW38 button was pressed at start up.\n" -msgstr "" - -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -msgid "The VOLUME button was pressed at start up.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"The `microcontroller` module was used to boot into safe mode. Press reset to " -"exit safe mode." +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" #: py/obj.c msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "The central button was pressed at start up.\n" -msgstr "" - -#: ports/nrf/boards/aramcon2_badge/mpconfigboard.h -msgid "The left button was pressed at start up.\n" -msgstr "" - #: shared-bindings/rgbmatrix/RGBMatrix.c msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" #: supervisor/shared/safe_mode.c -msgid "" -"The microcontroller's power dipped. Make sure your power supply provides\n" -"enough power for the whole circuit and press reset (after ejecting " -"CIRCUITPY)." +msgid "The power dipped. Make sure you are providing enough power." msgstr "" #: shared-module/audiomixer/MixerVoice.c @@ -2077,6 +2039,10 @@ msgstr "" msgid "The sample's signedness does not match the mixer's" msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "" + #: shared-module/imagecapture/ParallelImageCapture.c msgid "This microcontroller does not support continuous capture." msgstr "" @@ -2109,10 +2075,6 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "To exit, please reset the board without requesting safe mode." -msgstr "" - #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2204,6 +2166,10 @@ msgstr "" msgid "Unable to allocate buffers for signed conversion" msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate the heap." +msgstr "" + #: ports/espressif/common-hal/busio/I2C.c msgid "Unable to create lock" msgstr "" @@ -2409,13 +2375,44 @@ msgstr "" msgid "Writes not supported on Characteristic" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You are in safe mode because:\n" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" #: supervisor/shared/safe_mode.c -msgid "" -"You pressed the reset button during boot. Press again to exit safe mode." +msgid "You pressed the BOOT button at start up" +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" + +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" + +#: ports/nrf/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" #: supervisor/shared/micropython.c diff --git a/locale/cs.po b/locale/cs.po index 51ed1674f7..acda63fa4b 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -2428,6 +2428,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index 594e2005cc..5c519a09e2 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -2486,6 +2486,10 @@ msgstr "" "Du hast beim Booten die Reset-Taste gedrückt. Drücke sie erneut, um den " "abgesicherten Modus zu beenden." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() sollte None zurückgeben" diff --git a/locale/el.po b/locale/el.po index 7c816d4a9f..904d89846a 100644 --- a/locale/el.po +++ b/locale/el.po @@ -2437,6 +2437,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/en_GB.po b/locale/en_GB.po index ece9ec14f3..d9b6508b05 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -2444,6 +2444,10 @@ msgid "" msgstr "" "You pressed the reset button during boot. Press again to exit safe mode." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() should return None" diff --git a/locale/es.po b/locale/es.po index d40e92464c..141951b5c6 100644 --- a/locale/es.po +++ b/locale/es.po @@ -2494,6 +2494,10 @@ msgstr "" "Has presionado el botón de reset durante el arranque. Presiones de nuevo " "para salir del modo seguro." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() deberia devolver None" diff --git a/locale/fil.po b/locale/fil.po index 64a40976f5..4f7cf38dd7 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -2428,6 +2428,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() dapat magbalik na None" diff --git a/locale/fr.po b/locale/fr.po index 28f95530cb..58fbaf79a2 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -2512,6 +2512,10 @@ msgstr "" "Vous avez pressé le bouton reset pendant le démarrage. Pressez-le à nouveau " "pour sortir du mode sûr." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() doit retourner None" diff --git a/locale/hi.po b/locale/hi.po index 4fc15e35b4..84482dd969 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -2410,6 +2410,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/it_IT.po b/locale/it_IT.po index 85167249c6..f52f91e2fa 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -2438,6 +2438,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() deve ritornare None" diff --git a/locale/ja.po b/locale/ja.po index 5f2c6a7aa2..cd28a37893 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -2430,6 +2430,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 8a4ebc9082..a5f1c477e2 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -2414,6 +2414,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/nl.po b/locale/nl.po index 5122a036bc..f3c63f14e9 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -2440,6 +2440,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init __() zou None moeten retourneren" diff --git a/locale/pl.po b/locale/pl.po index 41c0c432a7..548c79e9d0 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -2421,6 +2421,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() powinien zwracać None" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 8d5e776397..50e1d38efc 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -2493,6 +2493,10 @@ msgstr "" "Você pressionou o botão reset durante a inicialização. Pressione-o novamente " "para sair do modo de segurança." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "O __init__() deve retornar Nenhum" diff --git a/locale/ru.po b/locale/ru.po index 205c1a1c0e..ab17fd486d 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -2478,6 +2478,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/sv.po b/locale/sv.po index 29fd45ca87..ee5591e015 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2023-01-29 16:16+0000\n" +"PO-Revision-Date: 2023-02-15 21:55+0000\n" "Last-Translator: Jonny Bergdahl \n" "Language-Team: LANGUAGE \n" "Language: sv\n" @@ -2466,6 +2466,10 @@ msgstr "" "Du tryckte på resetknappen under uppstarten. Tryck igen för att avsluta " "felsäkert läge." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "[trunkerad på grund av längd]" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init __() ska returnera None" @@ -2537,7 +2541,7 @@ msgstr "array har för många dimensioner" #: extmod/ulab/code/ndarray.c msgid "array is too big" -msgstr "" +msgstr "matrisen är för stor" #: py/objarray.c shared-bindings/alarm/SleepMemory.c #: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c @@ -3796,7 +3800,7 @@ msgstr "endast mono stöds" #: extmod/ulab/code/numpy/create.c msgid "only ndarrays can be concatenated" -msgstr "" +msgstr "endast ndarrays kan sammanfogas" #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only oversample=64 is supported" diff --git a/locale/tr.po b/locale/tr.po index 85a0d6af12..f856e50f0b 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -2436,6 +2436,10 @@ msgid "" "You pressed the reset button during boot. Press again to exit safe mode." msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 121a54dcbb..4299e116d2 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -2472,6 +2472,10 @@ msgstr "" "zài qǐ dòng guò chéng zhōng, nín àn xià le chóng zhì àn niǔ. zài cì àn xià " "yǐ tuì chū ān quán mó shì." +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + #: py/objtype.c msgid "__init__() should return None" msgstr "__init__() fǎnhuí not" diff --git a/main.c b/main.c index 1a622a9858..aa58dcf45f 100644 --- a/main.c +++ b/main.c @@ -384,7 +384,7 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) { } else { serial_write_compressed(translate("Auto-reload is off.\n")); } - if (safe_mode != NO_SAFE_MODE) { + if (safe_mode != SAFE_MODE_NONE) { serial_write_compressed(translate("Running in safe mode! Not running saved code.\n")); } } @@ -410,11 +410,11 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { // Do the filesystem flush check before reload in case another write comes // in while we're doing the flush. - if (safe_mode == NO_SAFE_MODE) { + if (safe_mode == SAFE_MODE_NONE) { stack_resize(); filesystem_flush(); } - if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) { + if (safe_mode == SAFE_MODE_NONE && !autoreload_pending()) { static const char *const supported_filenames[] = { "code.txt", "code.py", "main.py", "main.txt" }; @@ -538,7 +538,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { } else #endif if (_exec_result.return_code != PYEXEC_EXCEPTION) { - if (safe_mode == NO_SAFE_MODE) { + if (safe_mode == SAFE_MODE_NONE) { color = ALL_DONE; blink_count = ALL_DONE_BLINKS; } else { @@ -758,8 +758,34 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { vstr_t *boot_output; +#if CIRCUITPY_SAFEMODE_PY +STATIC void __attribute__ ((noinline)) run_safemode_py(safe_mode_t safe_mode) { + // Don't run if we aren't in safe mode or we won't be able to find safemode.py. + // 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) { - if (safe_mode == NO_HEAP) { + if (safe_mode == SAFE_MODE_NO_HEAP) { return; } @@ -767,7 +793,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { // There is USB setup to do even if boot.py is not actually run. const bool ok_to_run = filesystem_present() - && safe_mode == NO_SAFE_MODE + && safe_mode == SAFE_MODE_NONE && MP_STATE_VM(vfs_mount_table) != NULL; static const char *const boot_py_filenames[] = {"boot.py", "boot.txt"}; @@ -949,7 +975,7 @@ STATIC int run_repl(void) { int __attribute__((used)) main(void) { // initialise the cpu and peripherals - safe_mode_t safe_mode = port_init(); + set_safe_mode(port_init()); // Turn on RX and TX LEDs if we have them. init_rxtx_leds(); @@ -965,8 +991,8 @@ int __attribute__((used)) main(void) { serial_early_init(); // Wait briefly to give a reset window where we'll enter safe mode after the reset. - if (safe_mode == NO_SAFE_MODE) { - safe_mode = wait_for_safe_mode_reset(); + if (get_safe_mode() == SAFE_MODE_NONE) { + set_safe_mode(wait_for_safe_mode_reset()); } stack_init(); @@ -992,8 +1018,8 @@ int __attribute__((used)) main(void) { // Check whether CIRCUITPY is available. No need to reset to get safe mode // since we haven't run user code yet. - if (!filesystem_init(safe_mode == NO_SAFE_MODE, false)) { - safe_mode = NO_CIRCUITPY; + if (!filesystem_init(get_safe_mode() == SAFE_MODE_NONE, false)) { + set_safe_mode(SAFE_MODE_NO_CIRCUITPY); } #if CIRCUITPY_ALARM @@ -1018,16 +1044,23 @@ int __attribute__((used)) main(void) { supervisor_set_run_reason(RUN_REASON_STARTUP); // If not in safe mode turn on autoreload by default but before boot.py in case it wants to change it. - if (safe_mode == NO_SAFE_MODE) { + if (get_safe_mode() == SAFE_MODE_NONE) { autoreload_enable(); } // By default our internal flash is readonly to local python code and - // writable over USB. Set it here so that boot.py can change it. + // writable over USB. Set it here so that safemode.py or boot.py can change it. filesystem_set_internal_concurrent_write_protection(true); filesystem_set_internal_writable_by_usb(CIRCUITPY_USB == 1); - run_boot_py(safe_mode); + #if CIRCUITPY_SAFEMODE_PY + // Run safemode.py if we ARE in safe mode. + // If safemode.py does not do a hard reset, and exits normally, we will continue on + // and report the safe mode as usual. + run_safemode_py(get_safe_mode()); + #endif + + run_boot_py(get_safe_mode()); supervisor_workflow_start(); @@ -1052,7 +1085,7 @@ int __attribute__((used)) main(void) { // If code.py did a fake deep sleep, pretend that we // are running code.py for the first time after a hard // reset. This will preserve any alarm information. - skip_repl = run_code_py(safe_mode, &simulate_reset); + skip_repl = run_code_py(get_safe_mode(), &simulate_reset); } else { skip_repl = false; } @@ -1112,14 +1145,14 @@ void gc_collect(void) { } void NORETURN nlr_jump_fail(void *val) { - reset_into_safe_mode(MICROPY_NLR_JUMP_FAIL); + reset_into_safe_mode(SAFE_MODE_NLR_JUMP_FAIL); while (true) { } } #ifndef NDEBUG static void NORETURN __fatal_error(const char *msg) { - reset_into_safe_mode(MICROPY_FATAL_ERROR); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { } } diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h index 33910221a0..d7ca2a107c 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h @@ -23,7 +23,7 @@ #define CALIBRATE_CRYSTALLESS 1 // Explanation of how a user got into safe mode. -#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.") // Increase stack size slightly due to CPX library import nesting #define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8 diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h index 7f0e041f25..6ee5e0504b 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h @@ -23,7 +23,7 @@ #define CALIBRATE_CRYSTALLESS 1 // Explanation of how a user got into safe mode. -#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.") // Increase stack size slightly due to CPX library import nesting #define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8 diff --git a/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h index 12fd30e005..c0f2d07e9d 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +++ b/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h @@ -23,7 +23,7 @@ #define CALIBRATE_CRYSTALLESS 1 // Explanation of how a user got into safe mode. -#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.") // Increase stack size slightly due to CPX library import nesting. #define CIRCUITPY_DEFAULT_STACK_SIZE (4248) // divisible by 8 diff --git a/ports/atmel-samd/boards/meowmeow/mpconfigboard.h b/ports/atmel-samd/boards/meowmeow/mpconfigboard.h index ad6901230f..ab5f652d1e 100644 --- a/ports/atmel-samd/boards/meowmeow/mpconfigboard.h +++ b/ports/atmel-samd/boards/meowmeow/mpconfigboard.h @@ -6,7 +6,7 @@ #define CALIBRATE_CRYSTALLESS 1 // Explanation of how a user got into safe mode. -#define BOARD_USER_SAFE_MODE_ACTION translate("Both buttons were pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed both buttons at start up.") #define DEFAULT_I2C_BUS_SCL (&pin_PA01) #define DEFAULT_I2C_BUS_SDA (&pin_PA00) diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk index 0560da84fe..1e1bd31a24 100644 --- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk @@ -53,3 +53,13 @@ CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf # Override optimization to keep binary small 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 diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c index 60b35a2c5c..d1c02b360f 100644 --- a/ports/atmel-samd/common-hal/microcontroller/__init__.c +++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c @@ -51,9 +51,8 @@ void common_hal_mcu_disable_interrupts(void) { void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // This is very very bad because it means there was mismatched disable/enables so we - // "HardFault". - HardFault_Handler(); + // This is very very bad because it means there was mismatched disable/enables. + reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -76,7 +75,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { _bootloader_dbl_tap = DBL_TAP_MAGIC_QUICK_BOOT; } if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } } diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 57f7ca339f..d4d1ff31a3 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -57,6 +57,7 @@ CIRCUITPY_ZLIB = 0 ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) CIRCUITPY_ONEWIREIO ?= 0 +CIRCUITPY_SAFEMODE_PY ?= 0 CIRCUITPY_USB_IDENTIFICATION ?= 0 endif @@ -77,10 +78,8 @@ SUPEROPT_VM = 0 CIRCUITPY_LTO_PARTITION = one -ifeq ($(CIRCUITPY_FULL_BUILD),0) -# On the smallest boards, this saves about 180 bytes. On other boards, it may -increase- space used. +# On smaller builds this saves about 180 bytes. On other boards, it may -increase- space used, so use with care. CFLAGS_BOARD = -fweb -frename-registers -endif endif # samd21 ###################################################################### diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 2c63e28a17..45b999f1a1 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -368,20 +368,20 @@ safe_mode_t port_init(void) { #ifdef SAMD21 if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) { - return BROWNOUT; + return SAFE_MODE_BROWNOUT; } #endif #ifdef SAM_D5X_E5X if (RSTC->RCAUSE.bit.BODVDD == 1 || RSTC->RCAUSE.bit.BODCORE == 1) { - return BROWNOUT; + return SAFE_MODE_BROWNOUT; } #endif if (board_requests_safe_mode()) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { @@ -720,7 +720,7 @@ __attribute__((used)) void HardFault_Handler(void) { REG_MTB_MASTER = 0x00000000 + 6; #endif - reset_into_safe_mode(HARD_CRASH); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } diff --git a/ports/broadcom/common-hal/microcontroller/__init__.c b/ports/broadcom/common-hal/microcontroller/__init__.c index a1491d9668..53f04ebec3 100644 --- a/ports/broadcom/common-hal/microcontroller/__init__.c +++ b/ports/broadcom/common-hal/microcontroller/__init__.c @@ -46,7 +46,7 @@ void common_hal_mcu_disable_interrupts(void) { void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // reset_into_safe_mode(LOCKING_ERROR); + // reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { diff --git a/ports/broadcom/supervisor/port.c b/ports/broadcom/supervisor/port.c index fcb86674c5..ec6feb8703 100644 --- a/ports/broadcom/supervisor/port.c +++ b/ports/broadcom/supervisor/port.c @@ -78,10 +78,10 @@ safe_mode_t port_init(void) { // Check brownout. if (board_requests_safe_mode()) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { diff --git a/ports/cxd56/common-hal/microcontroller/__init__.c b/ports/cxd56/common-hal/microcontroller/__init__.c index dd9a54063f..c77a8829f2 100644 --- a/ports/cxd56/common-hal/microcontroller/__init__.c +++ b/ports/cxd56/common-hal/microcontroller/__init__.c @@ -74,7 +74,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { if (runmode == RUNMODE_BOOTLOADER) { mp_raise_ValueError(translate("Cannot reset into bootloader because no bootloader is present")); } else if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } } diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index dfd3cd6646..36d46dbad8 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -66,10 +66,10 @@ safe_mode_t port_init(void) { heap_size = size / sizeof(uint32_t); if (board_requests_safe_mode()) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_cpu(void) { diff --git a/ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h b/ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h index b7f2513217..4e9e679e5f 100644 --- a/ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h @@ -47,7 +47,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO38) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The SW38 button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the SW38 button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h b/ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h index 7de90b0ae8..49d49f2427 100644 --- a/ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +++ b/ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h @@ -35,7 +35,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The VOLUME button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the VOLUME button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h b/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h index 7d67267897..426d5c3bf7 100644 --- a/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h @@ -38,7 +38,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h b/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h index dfa12b53b0..9ec15fa0f2 100644 --- a/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h @@ -42,7 +42,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h b/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h index 926b7efbc4..77eba4ab92 100644 --- a/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h @@ -42,7 +42,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_atom_u/mpconfigboard.h b/ports/espressif/boards/m5stack_atom_u/mpconfigboard.h index b3b0a650ab..b5b2101134 100644 --- a/ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_atom_u/mpconfigboard.h @@ -41,7 +41,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("The central button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the central button at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_core_basic/mpconfigboard.h b/ports/espressif/boards/m5stack_core_basic/mpconfigboard.h index c974c64874..0135b66661 100755 --- a/ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_core_basic/mpconfigboard.h @@ -42,7 +42,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_core_fire/mpconfigboard.h b/ports/espressif/boards/m5stack_core_fire/mpconfigboard.h index f56a8fe901..2073473e1a 100755 --- a/ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_core_fire/mpconfigboard.h @@ -43,7 +43,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO39) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/boards/m5stack_stick_c/mpconfigboard.h b/ports/espressif/boards/m5stack_stick_c/mpconfigboard.h index aefdad1598..c80dbc9ee2 100644 --- a/ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_stick_c/mpconfigboard.h @@ -39,7 +39,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO37) // Explanation of how a user got into safe mode -#define BOARD_USER_SAFE_MODE_ACTION translate("Button A was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed button A at start up.") // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 68479dc46f..23c7c153e9 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -108,7 +108,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { break; case RUNMODE_SAFE_MODE: // enter safe mode on next boot - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); break; case RUNMODE_BOOTLOADER: // DFU download diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index b9c9790de4..a71825afa5 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -318,25 +318,25 @@ safe_mode_t port_init(void) { } if (heap == NULL) { heap_size = 0; - return NO_HEAP; + return SAFE_MODE_NO_HEAP; } esp_reset_reason_t reason = esp_reset_reason(); switch (reason) { case ESP_RST_BROWNOUT: - return BROWNOUT; + return SAFE_MODE_BROWNOUT; case ESP_RST_PANIC: - return HARD_CRASH; + return SAFE_MODE_HARD_FAULT; case ESP_RST_INT_WDT: // The interrupt watchdog is used internally to make sure that latency sensitive // interrupt code isn't blocked. User watchdog resets come through ESP_RST_WDT. - return WATCHDOG_RESET; + return SAFE_MODE_WATCHDOG; case ESP_RST_WDT: default: break; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { diff --git a/ports/litex/common-hal/microcontroller/__init__.c b/ports/litex/common-hal/microcontroller/__init__.c index 0a496d804e..1de55653fb 100644 --- a/ports/litex/common-hal/microcontroller/__init__.c +++ b/ports/litex/common-hal/microcontroller/__init__.c @@ -70,9 +70,8 @@ void common_hal_mcu_disable_interrupts(void) { __attribute__((section(".ramtext"))) void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // This is very very bad because it means there was mismatched disable/enables so we - // "HardFault". - asm ("ebreak"); + // This is very very bad because it means there was mismatched disable/enables. + reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -83,7 +82,7 @@ void common_hal_mcu_enable_interrupts(void) { void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } } diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 42d3a63920..45f9b91976 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -71,7 +71,7 @@ safe_mode_t port_init(void) { irq_setmask(0); irq_setie(1); tick_init(); - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } extern uint32_t _ebss; diff --git a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c index 8de63061ad..ded46b648e 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c @@ -52,12 +52,10 @@ void common_hal_mcu_disable_interrupts(void) { nesting_count++; } -void HardFault_Handler(void); void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // This is very very bad because it means there was mismatched disable/enables so we - // "HardFault". - HardFault_Handler(); + // This is very very bad because it means there was mismatched disable/enables + reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -80,7 +78,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { DBL_TAP_REG = DBL_TAP_MAGIC_QUICK_BOOT; } if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } } diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index fbf0e8a9d8..2ac7995943 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -259,10 +259,10 @@ safe_mode_t port_init(void) { // run yet, which uses `never_reset` to protect critical pins from being reset by `reset_port`. if (board_requests_safe_mode()) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { @@ -419,7 +419,7 @@ void port_idle_until_interrupt(void) { */ void MemManage_Handler(void); __attribute__((used)) void MemManage_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } @@ -430,7 +430,7 @@ __attribute__((used)) void MemManage_Handler(void) { */ void BusFault_Handler(void); __attribute__((used)) void BusFault_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } @@ -441,7 +441,7 @@ __attribute__((used)) void BusFault_Handler(void) { */ void UsageFault_Handler(void); __attribute__((used)) void UsageFault_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } @@ -452,7 +452,7 @@ __attribute__((used)) void UsageFault_Handler(void) { */ void HardFault_Handler(void); __attribute__((used)) void HardFault_Handler(void) { - reset_into_safe_mode(HARD_CRASH); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } diff --git a/ports/nrf/boards/aramcon2_badge/mpconfigboard.h b/ports/nrf/boards/aramcon2_badge/mpconfigboard.h index af8e3c3507..58df3a4058 100644 --- a/ports/nrf/boards/aramcon2_badge/mpconfigboard.h +++ b/ports/nrf/boards/aramcon2_badge/mpconfigboard.h @@ -52,7 +52,7 @@ #define CIRCUITPY_BOOT_BUTTON (&pin_P0_29) -#define BOARD_USER_SAFE_MODE_ACTION translate("The left button was pressed at start up.\n") +#define BOARD_USER_SAFE_MODE_ACTION translate("You pressed the left button at start up.") #define CIRCUITPY_INTERNAL_NVM_SIZE (4096) diff --git a/ports/nrf/common-hal/_bleio/Adapter.c b/ports/nrf/common-hal/_bleio/Adapter.c index 2c0c343877..1c3c829c5b 100644 --- a/ports/nrf/common-hal/_bleio/Adapter.c +++ b/ports/nrf/common-hal/_bleio/Adapter.c @@ -91,7 +91,7 @@ const nvm_bytearray_obj_t common_hal_bleio_nvm_obj = { }; STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { - reset_into_safe_mode(NORDIC_SOFT_DEVICE_ASSERT); + reset_into_safe_mode(SAFE_MODE_SDK_FATAL_ERROR); } bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index 7bf853fb30..cd4114dcfb 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -68,9 +68,8 @@ void common_hal_mcu_disable_interrupts() { void common_hal_mcu_enable_interrupts() { if (nesting_count == 0) { - // This is very very bad because it means there was mismatched disable/enables so we - // crash. - reset_into_safe_mode(HARD_CRASH); + // This is very very bad because it means there was mismatched disable/enables. + reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -88,7 +87,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { sd_power_gpregret_set(0,0); } if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } } diff --git a/ports/nrf/supervisor/internal_flash.c b/ports/nrf/supervisor/internal_flash.c index cce48a4c32..4229ec771b 100644 --- a/ports/nrf/supervisor/internal_flash.c +++ b/ports/nrf/supervisor/internal_flash.c @@ -75,7 +75,7 @@ void port_internal_flash_flush(void) { // Skip if data is the same if (memcmp(_flash_cache, (void *)_flash_page_addr, FLASH_PAGE_SIZE) != 0) { if (!nrf_nvm_safe_flash_page_write(_flash_page_addr, _flash_cache)) { - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } } } diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index e67f641900..313ecd7e44 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -77,7 +77,7 @@ extern void qspi_disable(void); #endif static void power_warning_handler(void) { - reset_into_safe_mode(BROWNOUT); + reset_into_safe_mode(SAFE_MODE_BROWNOUT); } uint32_t reset_reason_saved = 0; @@ -204,11 +204,11 @@ safe_mode_t port_init(void) { // If USB is connected, then the user might be editing `code.py`, // in which case we should reboot into Safe Mode. if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) { - return WATCHDOG_RESET; + return SAFE_MODE_WATCHDOG; } } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { @@ -399,7 +399,7 @@ void port_idle_until_interrupt(void) { extern void HardFault_Handler(void); void HardFault_Handler(void) { - reset_into_safe_mode(HARD_CRASH); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c index 327799a6e7..6d9b3d7fa0 100644 --- a/ports/raspberrypi/common-hal/microcontroller/__init__.c +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -60,7 +60,7 @@ void common_hal_mcu_disable_interrupts(void) { void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // reset_into_safe_mode(LOCKING_ERROR); + // reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -79,7 +79,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { next_reset_to_bootloader = true; break; case RUNMODE_SAFE_MODE: - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); break; default: break; diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 27012f2298..f3da71cbd7 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -161,10 +161,10 @@ safe_mode_t port_init(void) { } #endif if (board_requests_safe_mode()) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void reset_port(void) { @@ -312,7 +312,7 @@ __attribute__((used)) void HardFault_Handler(void) { REG_MTB_MASTER = 0x00000000 + 6; #endif - reset_into_safe_mode(HARD_CRASH); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } diff --git a/ports/stm/common-hal/canio/Listener.c b/ports/stm/common-hal/canio/Listener.c index 69c196b78d..0def8192f9 100644 --- a/ports/stm/common-hal/canio/Listener.c +++ b/ports/stm/common-hal/canio/Listener.c @@ -105,8 +105,7 @@ STATIC int next_filter(canio_can_obj_t *can) { return i; } } - reset_into_safe_mode(MICROPY_FATAL_ERROR); - return -1; + mp_raise_msg_varg(&mp_type_RuntimeError, translate("%q"), MP_QSTR_Listener); } // IDE = "extended ID" flag of packet header. We always add this bit to the diff --git a/ports/stm/common-hal/microcontroller/__init__.c b/ports/stm/common-hal/microcontroller/__init__.c index c399951f54..dc2e125a68 100644 --- a/ports/stm/common-hal/microcontroller/__init__.c +++ b/ports/stm/common-hal/microcontroller/__init__.c @@ -61,9 +61,8 @@ void common_hal_mcu_disable_interrupts(void) { void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { - // This is very very bad because it means there was mismatched disable/enables so we - // "HardFault". - asm ("bkpt"); + // This is very very bad because it means there was mismatched disable/enables. + reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); } nesting_count--; if (nesting_count > 0) { @@ -77,7 +76,7 @@ static bool next_reset_to_bootloader = false; void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { if (runmode == RUNMODE_SAFE_MODE) { - safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); + safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } if (runmode == RUNMODE_BOOTLOADER) { next_reset_to_bootloader = true; diff --git a/ports/stm/supervisor/internal_flash.c b/ports/stm/supervisor/internal_flash.c index e0f4153cb1..f3f9719753 100644 --- a/ports/stm/supervisor/internal_flash.c +++ b/ports/stm/supervisor/internal_flash.c @@ -215,7 +215,7 @@ void port_internal_flash_flush(void) { EraseInitStruct.NbSectors = 1; #endif if (sector_size > sizeof(_flash_cache) || sector_start_addr == 0xffffffff) { - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } // Skip if data is the same @@ -228,7 +228,7 @@ void port_internal_flash_flush(void) { if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { // error occurred during sector erase HAL_FLASH_Lock(); // lock the flash - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } uint32_t *cache_addr = (uint32_t *)_flash_cache; @@ -240,7 +240,7 @@ void port_internal_flash_flush(void) { (uint32_t)cache_addr) != HAL_OK) { // error occurred during flash write HAL_FLASH_Lock(); // lock the flash - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } // RAM memory is by word (4 byte), but flash memory is by byte cache_addr += 8; @@ -253,7 +253,7 @@ void port_internal_flash_flush(void) { *(uint64_t *)cache_addr) != HAL_OK) { // error occurred during flash write HAL_FLASH_Lock(); // lock the flash - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } // RAM memory is by word (4 byte), but flash memory is by byte cache_addr += 2; @@ -267,7 +267,7 @@ void port_internal_flash_flush(void) { (uint64_t)*cache_addr) != HAL_OK) { // error occurred during flash write HAL_FLASH_Lock(); // lock the flash - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } // RAM memory is by word (4 byte), but flash memory is by byte cache_addr += 1; @@ -335,7 +335,7 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block_num, // Fail for any sector outside what's supported by the cache if (sector_size > sizeof(_flash_cache)) { - reset_into_safe_mode(FLASH_WRITE_FAIL); + reset_into_safe_mode(SAFE_MODE_FLASH_WRITE_FAIL); } // Find how many blocks are left in the sector diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 97bd1c4982..1fb3f36377 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -211,7 +211,7 @@ safe_mode_t port_init(void) { // Turn off SysTick SysTick->CTRL = 0; - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void HAL_Delay(uint32_t delay_ms) { @@ -357,28 +357,28 @@ uint32_t port_get_saved_word(void) { } __attribute__((used)) void MemManage_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } } __attribute__((used)) void BusFault_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } } __attribute__((used)) void UsageFault_Handler(void) { - reset_into_safe_mode(MEM_MANAGE); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } } __attribute__((used)) void HardFault_Handler(void) { - reset_into_safe_mode(HARD_CRASH); + reset_into_safe_mode(SAFE_MODE_HARD_FAULT); while (true) { asm ("nop;"); } diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index be33d80a99..9de0e5a804 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -530,6 +530,11 @@ $(filter $(SRC_PATTERNS), \ wifi/Packet.c \ ) +ifeq ($(CIRCUITPY_SAFEMODE_PY),1) +SRC_BINDINGS_ENUMS += \ + supervisor/SafeModeReason.c +endif + SRC_BINDINGS_ENUMS += \ util.c diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 8ec338c372..4ea6ead794 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -372,6 +372,10 @@ CFLAGS += -DCIRCUITPY_ROTARYIO_SOFTENCODER=$(CIRCUITPY_ROTARYIO_SOFTENCODER) CIRCUITPY_RTC ?= 1 CFLAGS += -DCIRCUITPY_RTC=$(CIRCUITPY_RTC) +# Enable support for safemode.py +CIRCUITPY_SAFEMODE_PY ?= 1 +CFLAGS += -DCIRCUITPY_SAFEMODE_PY=$(CIRCUITPY_SAFEMODE_PY) + # CIRCUITPY_SAMD is handled in the atmel-samd tree. # Only for SAMD chips. # Assume not a SAMD build. diff --git a/py/gc.c b/py/gc.c index fc6bc90b67..0ced4c854d 100644 --- a/py/gc.c +++ b/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) { - reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM); + reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM); } GC_ENTER(); @@ -712,7 +712,7 @@ void gc_free(void *ptr) { GC_EXIT(); } else { if (MP_STATE_MEM(gc_pool_start) == 0) { - reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM); + reset_into_safe_mode(SAFE_MODE_GC_ALLOC_OUTSIDE_VM); } // get the GC block number corresponding to this pointer assert(VERIFY_PTR(ptr)); diff --git a/shared-bindings/microcontroller/ResetReason.c b/shared-bindings/microcontroller/ResetReason.c index 905c19f83f..13a8f25e6d 100644 --- a/shared-bindings/microcontroller/ResetReason.c +++ b/shared-bindings/microcontroller/ResetReason.c @@ -42,7 +42,7 @@ MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_ //| """The reason the microntroller was last reset""" //| //| POWER_ON: object -//| """The microntroller was started from power off.""" +//| """The microcontroller was started from power off.""" //| //| BROWNOUT: object //| """The microntroller was reset due to too low a voltage.""" diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index d250ae89c0..4d94172205 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -32,6 +32,7 @@ #include "shared-bindings/supervisor/RunReason.h" #include "shared-bindings/supervisor/Runtime.h" +#include "shared-bindings/supervisor/SafeModeReason.h" #include "supervisor/shared/reload.h" #include "supervisor/shared/stack.h" @@ -106,7 +107,7 @@ void supervisor_set_run_reason(supervisor_run_reason_t run_reason) { } //| run_reason: RunReason -//| """Why CircuitPython started running this particular time.""" +//| """Why CircuitPython started running this particular time (read-only).""" STATIC mp_obj_t supervisor_runtime_get_run_reason(mp_obj_t self) { return cp_enum_find(&supervisor_run_reason_type, _run_reason); } @@ -115,6 +116,23 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_run_reason_obj, supervisor_runt MP_PROPERTY_GETTER(supervisor_runtime_run_reason_obj, (mp_obj_t)&supervisor_runtime_get_run_reason_obj); +//| safe_mode_reason: SafeModeReason +//| """Why CircuitPython went into safe mode this particular time (read-only). +//| +//| **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 //| """Whether CircuitPython may autoreload based on workflow writes to the filesystem.""" //| @@ -198,6 +216,7 @@ STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_runtime_serial_bytes_available_obj) }, { MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_runtime_run_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_safe_mode_reason), MP_ROM_PTR(&supervisor_runtime_safe_mode_reason_obj) }, { MP_ROM_QSTR(MP_QSTR_autoreload), MP_ROM_PTR(&supervisor_runtime_autoreload_obj) }, { MP_ROM_QSTR(MP_QSTR_ble_workflow), MP_ROM_PTR(&supervisor_runtime_ble_workflow_obj) }, { MP_ROM_QSTR(MP_QSTR_rgb_status_brightness), MP_ROM_PTR(&supervisor_runtime_rgb_status_brightness_obj) }, diff --git a/shared-bindings/supervisor/Runtime.h b/shared-bindings/supervisor/Runtime.h index debc5ec79c..3c3e2611f6 100644 --- a/shared-bindings/supervisor/Runtime.h +++ b/shared-bindings/supervisor/Runtime.h @@ -31,12 +31,16 @@ #include "py/obj.h" #include "shared-bindings/supervisor/RunReason.h" +#include "shared-bindings/supervisor/SafeModeReason.h" extern const mp_obj_type_t supervisor_runtime_type; supervisor_run_reason_t supervisor_get_run_reason(void); void supervisor_set_run_reason(supervisor_run_reason_t run_reason); +safe_mode_t supervisor_get_safe_mode(void); +void supervisor_set_safe_mode(safe_mode_t safe_mode); + bool common_hal_supervisor_runtime_get_serial_connected(void); bool common_hal_supervisor_runtime_get_serial_bytes_available(void); diff --git a/shared-bindings/supervisor/SafeModeReason.c b/shared-bindings/supervisor/SafeModeReason.c new file mode 100644 index 0000000000..2da03bdced --- /dev/null +++ b/shared-bindings/supervisor/SafeModeReason.c @@ -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); diff --git a/shared-bindings/supervisor/SafeModeReason.h b/shared-bindings/supervisor/SafeModeReason.h new file mode 100644 index 0000000000..d061d75154 --- /dev/null +++ b/shared-bindings/supervisor/SafeModeReason.h @@ -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; diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index 2c84fbc0dd..491cac2f17 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -336,6 +336,11 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) }, { MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) }, { MP_ROM_QSTR(MP_QSTR_RunReason), MP_ROM_PTR(&supervisor_run_reason_type) }, + #if CIRCUITPY_SAFEMODE_PY + { MP_ROM_QSTR(MP_QSTR_SafeModeReason), MP_ROM_PTR(&supervisor_safe_mode_reason_type) }, + #else + { MP_ROM_QSTR(MP_QSTR_SafeModeReason), MP_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_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) }, diff --git a/supervisor/messages/default.h b/supervisor/messages/default.h deleted file mode 100644 index 8cdd671b31..0000000000 --- a/supervisor/messages/default.h +++ /dev/null @@ -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 diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index c7e93e6393..5112b17ebf 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -43,20 +43,28 @@ #define SAFE_MODE_DATA_GUARD 0xad0000af #define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff -static safe_mode_t current_safe_mode; +static safe_mode_t _safe_mode; + +safe_mode_t get_safe_mode(void) { + return _safe_mode; +} + +void set_safe_mode(safe_mode_t safe_mode) { + _safe_mode = safe_mode; +} safe_mode_t wait_for_safe_mode_reset(void) { uint32_t reset_state = port_get_saved_word(); - safe_mode_t safe_mode = NO_SAFE_MODE; + safe_mode_t safe_mode = SAFE_MODE_NONE; if ((reset_state & SAFE_MODE_DATA_GUARD_MASK) == SAFE_MODE_DATA_GUARD) { safe_mode = (reset_state & ~SAFE_MODE_DATA_GUARD_MASK) >> 8; } - if (safe_mode != NO_SAFE_MODE) { + if (safe_mode != SAFE_MODE_NONE) { port_set_saved_word(SAFE_MODE_DATA_GUARD); - current_safe_mode = safe_mode; + _safe_mode = safe_mode; return safe_mode; } else { - current_safe_mode = 0; + _safe_mode = SAFE_MODE_NONE; } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); @@ -64,12 +72,12 @@ safe_mode_t wait_for_safe_mode_reset(void) { reset_reason != RESET_REASON_RESET_PIN && reset_reason != RESET_REASON_UNKNOWN && reset_reason != RESET_REASON_SOFTWARE) { - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } #if CIRCUITPY_SKIP_SAFE_MODE_WAIT - return NO_SAFE_MODE; + return SAFE_MODE_NONE; #endif - port_set_saved_word(SAFE_MODE_DATA_GUARD | (MANUAL_SAFE_MODE << 8)); + port_set_saved_word(SAFE_MODE_DATA_GUARD | (SAFE_MODE_USER << 8)); // Wait for a while to allow for reset. #if CIRCUITPY_STATUS_LED @@ -106,11 +114,11 @@ safe_mode_t wait_for_safe_mode_reset(void) { status_led_deinit(); #endif if (boot_in_safe_mode) { - return USER_SAFE_MODE; + return SAFE_MODE_USER; } // Restore the original state of the saved word if no reset occured during our wait period. port_set_saved_word(reset_state); - return NO_SAFE_MODE; + return SAFE_MODE_NONE; } void safe_mode_on_next_reset(safe_mode_t reason) { @@ -119,7 +127,7 @@ void safe_mode_on_next_reset(safe_mode_t reason) { // Don't inline this so it's easy to break on it from GDB. void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) { - if (current_safe_mode > BROWNOUT && reason > BROWNOUT) { + if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) { while (true) { // This very bad because it means running in safe mode didn't save us. Only ignore brownout // because it may be due to a switch bouncing. @@ -133,105 +141,95 @@ void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) { void print_safe_mode_message(safe_mode_t reason) { - if (reason == NO_SAFE_MODE) { + if (reason == SAFE_MODE_NONE) { return; } - serial_write("\r\n"); - serial_write_compressed(translate("You are in safe mode because:\n")); + serial_write_compressed(translate("\nYou are in safe mode because:\n")); const compressed_string_t *message = NULL; // First check for safe mode reasons that do not necessarily reflect bugs. switch (reason) { - case USER_SAFE_MODE: + case SAFE_MODE_BROWNOUT: + message = translate("The power dipped. Make sure you are providing enough power."); + break; + case SAFE_MODE_USER: #if defined(BOARD_USER_SAFE_MODE_ACTION) message = BOARD_USER_SAFE_MODE_ACTION; #elif defined(CIRCUITPY_BOOT_BUTTON) - message = translate("The BOOT button was pressed at start up.\n"); - #endif - #if defined(BOARD_USER_SAFE_MODE_ACTION) || defined(CIRCUITPY_BOOT_BUTTON) - // Output a user safe mode string if it's set. - serial_write_compressed(message); - message = translate("To exit, please reset the board without requesting safe mode."); - // The final piece is printed below. + message = translate("You pressed the BOOT button at start up"); + #else + message = translate("You pressed the reset button during boot."); #endif break; - case MANUAL_SAFE_MODE: - message = translate("You pressed the reset button during boot. Press again to exit safe mode."); + case SAFE_MODE_NO_CIRCUITPY: + message = translate("CIRCUITPY drive could not be found or created."); break; - case PROGRAMMATIC_SAFE_MODE: - message = translate("The `microcontroller` module was used to boot into safe mode. Press reset to exit safe mode."); + case SAFE_MODE_PROGRAMMATIC: + message = translate("The `microcontroller` module was used to boot into safe mode."); break; - case BROWNOUT: - message = translate("The microcontroller's power dipped. Make sure your power supply provides\nenough power for the whole circuit and press reset (after ejecting CIRCUITPY)."); + #if CIRCUITPY_SAFEMODE_PY + case SAFE_MODE_SAFEMODE_PY_ERROR: + message = translate("Error in safemode.py."); 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."); break; - case USB_TOO_MANY_INTERFACE_NAMES: + case SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES: message = translate("USB devices specify too many interface names."); break; - case USB_BOOT_DEVICE_NOT_INTERFACE_ZERO: - message = translate("Boot device must be first device (interface #0)."); + case SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO: + message = translate("Boot device must be first (interface #0)."); break; - case WATCHDOG_RESET: + case SAFE_MODE_WATCHDOG: message = translate("Internal watchdog timer expired."); break; - case NO_CIRCUITPY: - message = translate("CIRCUITPY drive could not be found or created."); - break; default: break; } if (message) { + // Non-crash safe mode. serial_write_compressed(message); - serial_write("\r\n"); - return; + } else { + // 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. - - 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")); + // Always tell user how to get out of safe mode. + serial_write_compressed(translate("\nPress reset to exit safe mode.\n")); } diff --git a/supervisor/shared/safe_mode.h b/supervisor/shared/safe_mode.h index 0c8d018bfe..005488552e 100644 --- a/supervisor/shared/safe_mode.h +++ b/supervisor/shared/safe_mode.h @@ -30,27 +30,32 @@ #include "py/mpconfig.h" typedef enum { - NO_SAFE_MODE = 0, - BROWNOUT, - HARD_CRASH, - USER_SAFE_MODE, - HEAP_OVERWRITTEN, - MANUAL_SAFE_MODE, - MICROPY_NLR_JUMP_FAIL, - MICROPY_FATAL_ERROR, - GC_ALLOC_OUTSIDE_VM, - PROGRAMMATIC_SAFE_MODE, - NORDIC_SOFT_DEVICE_ASSERT, - FLASH_WRITE_FAIL, - MEM_MANAGE, - WATCHDOG_RESET, - USB_TOO_MANY_ENDPOINTS, - USB_TOO_MANY_INTERFACE_NAMES, - USB_BOOT_DEVICE_NOT_INTERFACE_ZERO, - NO_HEAP, - NO_CIRCUITPY, + SAFE_MODE_NONE = 0, + // BROWNOUT should be lowest after SAFE_MODE_NONE. + SAFE_MODE_BROWNOUT, + // alphabetical from here down + SAFE_MODE_FLASH_WRITE_FAIL, + SAFE_MODE_GC_ALLOC_OUTSIDE_VM, + SAFE_MODE_HARD_FAULT, + SAFE_MODE_INTERRUPT_ERROR, + SAFE_MODE_MANUAL, + SAFE_MODE_NLR_JUMP_FAIL, + SAFE_MODE_NO_CIRCUITPY, + SAFE_MODE_NO_HEAP, + SAFE_MODE_PROGRAMMATIC, + SAFE_MODE_SAFEMODE_PY_ERROR, + SAFE_MODE_SDK_FATAL_ERROR, + SAFE_MODE_STACK_OVERFLOW, + SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO, + SAFE_MODE_USB_TOO_MANY_ENDPOINTS, + SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES, + SAFE_MODE_USER, + SAFE_MODE_WATCHDOG, } safe_mode_t; +safe_mode_t get_safe_mode(void); +void set_safe_mode(safe_mode_t safe_mode); + safe_mode_t wait_for_safe_mode_reset(void); void safe_mode_on_next_reset(safe_mode_t reason); diff --git a/supervisor/shared/stack.c b/supervisor/shared/stack.c index fa8d019fea..be97cee234 100644 --- a/supervisor/shared/stack.c +++ b/supervisor/shared/stack.c @@ -74,7 +74,7 @@ inline bool stack_ok(void) { inline void assert_heap_ok(void) { if (!stack_ok()) { - reset_into_safe_mode(HEAP_OVERWRITTEN); + reset_into_safe_mode(SAFE_MODE_STACK_OVERFLOW); } } diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c index fa4cf9607e..e7cffee351 100644 --- a/supervisor/shared/usb/usb_desc.c +++ b/supervisor/shared/usb/usb_desc.c @@ -228,7 +228,7 @@ static void usb_build_configuration_descriptor(void) { if (usb_hid_boot_device() > 0 && descriptor_counts.current_interface > 0) { // Hosts using boot devices generally to expect them to be at interface zero, // and will not work properly otherwise. - reset_into_safe_mode(USB_BOOT_DEVICE_NOT_INTERFACE_ZERO); + reset_into_safe_mode(SAFE_MODE_USB_BOOT_DEVICE_NOT_INTERFACE_ZERO); } descriptor_buf_remaining += usb_hid_add_descriptor( descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string, @@ -258,14 +258,14 @@ static void usb_build_configuration_descriptor(void) { if (descriptor_counts.current_endpoint > USB_NUM_ENDPOINT_PAIRS || descriptor_counts.num_in_endpoints > USB_NUM_IN_ENDPOINTS || descriptor_counts.num_out_endpoints > USB_NUM_OUT_ENDPOINTS) { - reset_into_safe_mode(USB_TOO_MANY_ENDPOINTS); + reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_ENDPOINTS); } } // str must not be on the heap. void usb_add_interface_string(uint8_t interface_string_index, const char str[]) { if (interface_string_index > MAX_INTERFACE_STRINGS) { - reset_into_safe_mode(USB_TOO_MANY_INTERFACE_NAMES); + reset_into_safe_mode(SAFE_MODE_USB_TOO_MANY_INTERFACE_NAMES); } collected_interface_strings[interface_string_index].char_str = str; diff --git a/supervisor/stub/safe_mode.c b/supervisor/stub/safe_mode.c index b62cc05d78..ea5187da28 100644 --- a/supervisor/stub/safe_mode.c +++ b/supervisor/stub/safe_mode.c @@ -29,7 +29,7 @@ #include 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) {