metronome/pico-cp/boot.py
Me Here 7d743c18a1 PM_K-1: appliance model — push-programming over USB-MIDI, on-device practice log, swing fix
Firmware (pico-cp/): the Pico now owns its filesystem by default (boot.py), so it can save the
practice log and write editor-pushed set lists; the drive is read-only to the computer, which also
protects the firmware. Hold button A at power-on for editor mode (drive writable; universal drag).
  - Replaced the on-screen touch buttons with an on-device PRACTICE LOG (time · BPM · duration ·
    track), newest-first, persisted to /history.json next to programs.json. Plays < 5s aren't logged;
    tap a row twice to delete it. Real timestamps once the editor syncs the clock.
  - USB-MIDI SysEx receiver: clock-set (0x01 -> RTC) and program-push (0x10 -> write programs.json,
    reload, ACK/NAK). disable autoreload so our own writes never self-restart.
  - Fixed swing: the parser was discarding the 's' flag, so /2s never swung. Now the scheduler uses a
    per-step duration with long-short (2:1, SWING_RATIO 2/3) pairs on even subdivisions, matching the
    web engine. Verified: ride:4/2s -> 266/133ms vs straight 200/200.

Editor (editor.html): requestMIDIAccess({sysex:true}); Save to device now pushes programs.json as
SysEx to the device (+ clock sync), waits for ACK, shows "Saved ✓", and falls back to downloading the
file (drag onto the drive in editor mode) when no device answers. Heartbeat also keeps the clock synced.
Web MIDI works in Chromium AND Firefox; the drag fallback covers any browser/OS incl. Safari.

Docs (pico-cp/README, info-kit, README) updated for the two modes, push programming, and the log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:38:08 -05:00

22 lines
1.1 KiB
Python

# boot.py — runs once at power-on (before USB connects); decides who owns the filesystem.
#
# DEFAULT = appliance mode: the FIRMWARE owns the drive, so it can save your practice log to
# /history.json and write /programs.json that the editor pushes over USB-MIDI. The drive is then
# READ-ONLY to the computer — which also protects the firmware from accidental deletion.
#
# HOLD BUTTON A (GP15) WHILE PLUGGING IN = editor mode: the drive is writable by the computer, so
# you can drag programs.json / code.py on from any OS or browser (the universal fallback). Reset
# afterwards to return to appliance mode.
#
# Also frees a USB endpoint (disables unused HID) and makes sure USB-MIDI is available.
import board, digitalio, storage, usb_hid, usb_midi
try: usb_hid.disable()
except Exception: pass
usb_midi.enable()
a = digitalio.DigitalInOut(board.GP15)
a.switch_to_input(pull=digitalio.Pull.UP)
appliance = a.value # value True (pull-up, not pressed) -> appliance mode
a.deinit()
if appliance:
try: storage.remount("/", readonly=False) # writable by code, read-only to the computer
except Exception: pass