Skip to content

Instantly share code, notes, and snippets.

@anecdata
Last active May 29, 2024 08:30
Show Gist options
  • Save anecdata/fe35dc6a94069fc920edf61a64750b53 to your computer and use it in GitHub Desktop.
Save anecdata/fe35dc6a94069fc920edf61a64750b53 to your computer and use it in GitHub Desktop.
CircuitPython 8 safemode.py
# SPDX-FileCopyrightText: 2023 anecdata
#
# SPDX-License-Identifier: MIT
import json
import microcontroller
import supervisor
from ⚙️ import *
# safemode.py is the entry point for SAFE MODE (hard fault, etc.)
# store supervisor.runtime.safe_mode_reason since it won't be available during boot.py or code.py
# NVM Safe Mode - to cross-check against safemode reason
if microcontroller.nvm[NVM_INDEX_SAFEMODE] != SAFEMODESET:
microcontroller.nvm[NVM_INDEX_SAFEMODE] = SAFEMODESET
# set up the safemode dict
safemode_dict = {}
safemode_dict["safemode_reason"] = str(supervisor.runtime.safe_mode_reason)
update_restart_dict_time(safemode_dict) # add timestamp
# write dict as JSON
precode_file_write("/safemode.json", json.dumps(safemode_dict)) # use storage.remount()
if False: # check for any safemode conditions where we shouldn't RESET
pass
else:
# RESET out of safe mode
microcontroller.reset() # or alarm.exit_and_deep_sleep()
@anecdata
Copy link
Author

Nice. Yeah, my intention was to highlight the features of safemode.py, and carrying data forward through into boot.py and code.py. Hopefully folks modify and extend it to better suit their needs.

print() in safemode.py goes nowhere, hence the file write and nvm. print() in boot.py also goes nowhere except for getting appended to boot_out.txt, up to 512 bytes total (no serial console / REPL until [re]load / run time / code.py).

I mostly work with espressif and raspberrypi ports, and there are some differences that may be beneficial in either case. For example, espressif maintains the on-chip RTC time across soft resets, whereas raspberrypi does not. Also, there is a new PR to add sleep_memory on the raspberrypi port, and in that case sleep_memory survives not only deep sleep and reloads, but also soft resets (microcontroller.reset()).

@anecdata
Copy link
Author

Adafruit Learn Guide: "CircuitPython Safe Mode"
https://learn.adafruit.com/circuitpython-safe-mode

Adafruit Learn Guide: "CircuitPython Essentials: CircuitPython Storage" (writing to flash)
https://learn.adafruit.com/circuitpython-essentials/circuitpython-storage

@todbot
Copy link

todbot commented Jun 25, 2023

nice!

@DJDevon3
Copy link

Emoji's as imports. What is this chaos... I love it.

@todbot
Copy link

todbot commented Jan 30, 2024

from 💣 import TotallySafeCodeNotA💥

@DJDevon3
Copy link

from 📷import 🖼️ I could see some neat uses.

@vladak
Copy link

vladak commented May 29, 2024

I wonder how do you test safemode.py. The documentation mentions supervisor.SafeModeReason.PROGRAMMATIC however there is not much about how to trigger it. I tried blowing the stack in code.py however that ends up with RuntimeError.

edit: I see now, the guide on https://learn.adafruit.com/circuitpython-safe-mode/safe-mode-reasons describes how to do it using microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment