PM_K-1: add firmware-protect helper (hide files so users only see editor + programs)

protect-firmware.sh sets the FAT hidden attribute on the firmware files (code.py, boot.py,
font_*.bin, README) on a mounted CIRCUITPY drive, so an end user sees only editor.html +
programs.json and can't accidentally delete the program — the hidden files keep running and
Save to device still works. Documented in pico-cp/README (incl. the read-only boot.py
hard-lock alternative) and bundled into pm_k1_circuitpy.zip. README.md verified accurate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-05-28 23:58:12 -05:00
parent 4ceb80b4f4
commit 09b20a9e69
3 changed files with 43 additions and 1 deletions

View file

@ -39,7 +39,8 @@ pathlib.Path("dist/pico-main.py").write_text(pathlib.Path("pico/main.py").read_t
print("copied pico-main.py") print("copied pico-main.py")
import zipfile # PM_K-1 CircuitPython drive bundle (download → unzip onto CIRCUITPY) import zipfile # PM_K-1 CircuitPython drive bundle (download → unzip onto CIRCUITPY)
with zipfile.ZipFile("dist/pm_k1_circuitpy.zip", "w", zipfile.ZIP_DEFLATED) as z: with zipfile.ZipFile("dist/pm_k1_circuitpy.zip", "w", zipfile.ZIP_DEFLATED) as z:
for f in ("code.py", "boot.py", "programs.json", "font_s.bin", "font_m.bin", "font_l.bin", "README.md"): for f in ("code.py", "boot.py", "programs.json", "font_s.bin", "font_m.bin", "font_l.bin",
"README.md", "protect-firmware.sh"):
z.write("pico-cp/" + f, f) z.write("pico-cp/" + f, f)
z.write("dist/editor.html", "editor.html") # offline copy of the editor, on the drive z.write("dist/editor.html", "editor.html") # offline copy of the editor, on the drive
print("zipped pm_k1_circuitpy.zip") print("zipped pm_k1_circuitpy.zip")

View file

@ -36,6 +36,21 @@ If the editor says **no MIDI input is connected**, copy **`boot.py`** onto `CIRC
**power-cycle** the Pico (`boot.py` only runs on a full reset). It frees a USB endpoint (drops the **power-cycle** the Pico (`boot.py` only runs on a full reset). It frees a USB endpoint (drops the
unused HID interface) so the MIDI port is guaranteed to appear alongside the drive. unused HID interface) so the MIDI port is guaranteed to appear alongside the drive.
## Protect the firmware (so end users only see the editor + their tracks)
To stop someone accidentally deleting the firmware, **hide it** — the files keep running and
"Save to device" still works, but only `editor.html` + `programs.json` show in the file browser.
On the host, with the drive mounted, run the included helper (needs `fatattr`):
```
./protect-firmware.sh /media/$USER/CIRCUITPY # hides code.py, boot.py, font_*.bin, README, itself
```
(Reveal again with `fatattr -h <file>`.) For a **hard lock** — nothing on the drive can be changed
from the computer at all — put `storage.remount("/", readonly=True)` in `boot.py`; but then the
editor's *Save to device* can't write either, so you'd reprogram by temporarily removing that line
(or gating it behind a held button at power-on). Hiding is usually the right balance.
## Controls (same as the MicroPython build) ## Controls (same as the MicroPython build)
- **Touch:** onscreen `◀◀ / ▶ / ▶▶` (prev · play/stop · next) and ` / TAP / +`. - **Touch:** onscreen `◀◀ / ▶ / ▶▶` (prev · play/stop · next) and ` / TAP / +`.

26
pico-cp/protect-firmware.sh Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Hide the PM_K-1 firmware files on a CIRCUITPY drive so an end user only sees
# editor.html + programs.json — the two files they're meant to touch. The hidden
# files keep running, and the editor's "Save to device" still works (programs.json
# stays writable). This just prevents *accidental* deletion of the firmware.
#
# Run it on the HOST, pointing at the mounted drive:
# ./protect-firmware.sh /media/$USER/CIRCUITPY
# (defaults to the current directory if run from inside the drive). Needs `fatattr`
# (sudo apt install fatattr) — or use the mtools fallback printed below.
#
# To reveal them again: fatattr -h <file>
set -euo pipefail
DIR="${1:-.}"
HIDE=(code.py boot.py font_s.bin font_m.bin font_l.bin README.md protect-firmware.sh boot_out.txt)
if command -v fatattr >/dev/null 2>&1; then
for f in "${HIDE[@]}"; do
if [ -e "$DIR/$f" ]; then fatattr +h "$DIR/$f" && echo "hidden: $f"; fi
done
echo "Done — the drive now shows only editor.html + programs.json."
else
echo "fatattr not found. Install it: sudo apt install fatattr (or dnf/pacman equivalent)"
echo "Or, with mtools, run e.g.: mattrib -i /dev/sdX1 +h ::code.py ::boot.py ::font_*.bin"
exit 1
fi