Split the CircuitPython firmware into a tiny stable loader (code.py) + the application (app.py, carries APP_VERSION). The editor's ⋯ → "⬆ Update firmware" queries the device version (SysEx 0x02 -> 0x03 reply), fetches the latest app from the site (/pico-cp-app.py), shows device-vs-latest, and pushes the new app.py over USB-MIDI (SysEx 0x20). The device installs it to a trial slot (old build kept as app.bak), reboots, and the loader AUTO-ROLLS-BACK to app.bak if the new build fails to start; a build that runs cleanly ~5s is confirmed (clears /trial). No BOOTSEL, no dragging; Chromium/Firefox. app.py forced to pure ASCII so it pushes raw (no base64); SysEx buffer raised to 60KB. build.sh/deploy.sh: bundle code.py+app.py and serve /pico-cp-app.py. Docs updated. Verified in CPython: version reply, update install+reboot+ACK, rollback file dance; editor loads clean with the updater wired. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
23 lines
1.2 KiB
Python
23 lines
1.2 KiB
Python
# code.py - PM_K-1 A/B firmware loader (stable; rarely changes).
|
|
#
|
|
# The real application lives in app.py; app.bak holds the previous known-good build. The web editor
|
|
# pushes a new app.py to a "trial" slot over USB-MIDI; this loader runs it, and if the new build
|
|
# fails to boot it AUTOMATICALLY ROLLS BACK to app.bak. (The Pico is also unbrickable: BOOTSEL ->
|
|
# drag a CircuitPython .uf2.) app.py clears the /trial marker once it has run healthily for ~5s.
|
|
import supervisor, os
|
|
supervisor.runtime.autoreload = False # updates reboot explicitly; never auto-restart on our own writes
|
|
|
|
def _trial():
|
|
try: os.stat("/trial"); return True
|
|
except OSError: return False
|
|
|
|
try:
|
|
import app # runs the application (app.py ends with App().run())
|
|
except Exception:
|
|
if _trial(): # a freshly-pushed build crashed on startup -> roll back
|
|
try:
|
|
os.remove("/app.py"); os.rename("/app.bak", "/app.py"); os.remove("/trial")
|
|
except Exception: pass
|
|
supervisor.reload() # reboot into the restored known-good build
|
|
else:
|
|
raise # the active build failed unexpectedly (rare) -> on-screen traceback
|