Hold both buttons at power-on to enter a self-contained jog screen: the joystick spins the stepper CW/CCW (speed by deflection), with an on-screen direction needle + RGB LED feedback. Runs in its own loop; power-cycle to return to normal. - app.py: _jog_loop drawn entirely in the overlay group (cover + labels + needle); Pendulum.spin() does a free half-step either way; _jog set when A+B held in init; run() branches to it before the normal loop. - boot.py: editor mode is now "A alone" (A pressed, B not). A+B stays in appliance mode, so the jog chord doesn't also flip the drive writable. Pure ASCII; conformance 47/47; build precompiles app.mpy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
25 lines
1.4 KiB
Python
25 lines
1.4 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) ALONE 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.
|
|
#
|
|
# HOLD BUTTON A + B TOGETHER = the firmware's hidden stepper jog/test mode (app.py). That chord
|
|
# stays in appliance mode here (drive NOT flipped writable) so testing doesn't disturb the drive.
|
|
#
|
|
# 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)
|
|
b = digitalio.DigitalInOut(board.GP14); b.switch_to_input(pull=digitalio.Pull.UP)
|
|
editor = (not a.value) and b.value # editor mode = A pressed, B NOT pressed (A+B is the jog chord)
|
|
a.deinit(); b.deinit()
|
|
if not editor:
|
|
try: storage.remount("/", readonly=False) # appliance: writable by code, read-only to the computer
|
|
except Exception: pass
|