Skip to content

tools: rescue mode, simulator skin and audio, pedal log reader, scan helper, verify skill - #15

Merged
isod89 merged 33 commits into
isod89:mainfrom
VinSpee:fm/openpocket-upstream-devtools
Nov 8, 2026
Merged

isod89 merged 33 commits into
isod89:mainfrom
VinSpee:fm/openpocket-upstream-devtools

Conversation

@VinSpee

@VinSpee VinSpee commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

This depends on #11, #12 and #13, and it stays a draft until they merge. The branch merges their head branches, so the diff includes their changes for now. The new work is the 15 commits after those three merges. The two log channel commits also appear in #16, which needs them, and they drop out of whichever of the two merges second.

It adds five developer tools. node tools/op.mjs flash --rescue waits for a pedal that restarts in a loop and then installs. The simulator gains the pedal's front panel as its page. It also plays audio through the real engine, built to WebAssembly, from five CC BY 4.0 guitar loops or a computer input. The Bluetooth test image gains a read-only DIAG request, and node tools/op.mjs log prints that reading with a verdict. tools/ble-scan.swift adds --scan to that command, and the verify-pedal skill describes the whole check: flash, read, scan and report.

On a real pedal, op.mjs log read the test image's status over USB with no one reading the screen, and it fell back correctly on firmware without DIAG. The Mac scan also ran against a real pedal and reported FAIL, which was correct because the radio on this branch is still silent. The radio fix is in the Bluetooth PR, so a PASS has not been seen from this branch.

flash --rescue has run only against the simulated pedal, and the last-boot failure report has run only in the simulator. node tools/op.mjs test, build and ble pass on this branch. The Playwright page tests, including the front panel tests, did not run because Playwright is not in the build image.

A separate build target that links JieLi's Apache-2.0 LE controller
(third_party/jieli-ble) into the normal firmware and sends one scannable
advertisement named OpenPocket-BLE-TEST with the BLE-MIDI service UUID.
No connections, pairing or MIDI over Bluetooth. The normal firmware and
installer packages are byte-identical; the VM and BTIF areas are not touched.

Built, linked and packaged; not yet run on a pedal (docs/BLE-TEST.md lists
what is unverified).
… and refuse a link that would trip it

The first hardware run faulted at the first instruction of the first BLE task (EMU bit 3, stack limit):
the task stacks lie outside [_ustack_lo, _sstack_top]. The test image is now built with FM1_GUARD_STACK off
(OP_GUARD_STACK=0); the normal firmware is byte-identical. app.ld fails the link if the stack guard is on while the
task stacks are outside the window. docs/BLE-TEST.md lists the other guards as checked on paper only.
… full failure line

The status text now reads STARTING <stage> or FAILED <step> <code>; a timeout names the stage it stalled in. On FAILED the
whole line (step and stage in words) scrolls across the status area in the 500 ms redraw. The logic is in ble_status.h and
tested on the PC (tests/test_ble_status.c). The normal firmware is byte-identical.
… and two related fixes

The controller task deadlocked in ll_init -> thread_create -> crc_get_32bit: the lock is created by the vendor
__crc16_mutex_init(), which only the SDK's own start-up calls (FAILED 5 3 on the pedal). ble_test_start now calls it.
ll_hci_adv_set_params gets a six-byte direct address instead of NULL (the library reads six bytes), and the context
switch saves r4-r15, the registers the compiler preserves. The failure line gains two stage markers (radio replay
returned, baseband interrupts requested) and, at a timeout, the object the controller task waits on.
Normal firmware is byte-identical. Not run on a pedal.
…p Bluetooth off after a failed boot

The third hardware run froze in the first ble_poll: the library asserts the handle low_power_get returns, our empty
stand-in returned null, and a failed assertion parks in P33_SYSTEM_RESET (an endless loop) until the watchdog resets.
low_power_get now returns a non-null handle. A stall watch in the 10 kHz timer tick turns a ble_poll that has not
returned after 4 s into the normal crash screen (VEC 63, PC and RETS of the stuck code). Bluetooth is not started on a
boot that follows a failed one, so the boot guard cannot send the pedal to the loader. Normal firmware is byte-identical.
…ash skill

The flasher reuses docs/pxota.js and docs/pxpkg.js, the modules the installer page runs.
It requires --confirm-flash for any write, supports --dry-run, checks the package
against the manifest SHA-256, refuses the wrong model, verifies the version the pedal
reports, and prints the SD-card recovery pointer on failure. Tested against the
simulated pedal.
…Web MIDI shim

tests/edsim.c now also runs the pedal's screen (ui.h, via the shared tests/simlcd.h) and
the control dispatch, and keeps its flash in a file (--persist). tools/sim.mjs hosts it:
press/knob/state/screen/flash/SysEx API, a control page, and the installer and editor
pages with a virtual Web MIDI injected. --update hosts tests/devsim.c for the installer.
Adds tests/test_sim.mjs, docs/SIMULATOR.md and the openpocket-simulator skill; the verify
and toolchain skills point to it. The stdin/stdout contract of devsim and edsim is kept.
… spec check of the advertisement

The fourth flash showed ADVERTISING but no scanner saw the pedal. While advertising, the status now scrolls counters of
the two baseband interrupts (counted by ble_isr.S before the library's handlers run), HCI packets returned, library
timers fired, slot-timer stand-in calls, and the baseband, interrupt-config and block-enable registers. The controller's
public address was never set (all zeros): it is now a fixed non-zero locally administered address. The advertisement is
in ble_adv.h and tests/test_ble_status.c checks it against the Core Specification. Normal firmware is byte-identical.
Waits for a pedal that restarts in a loop, stops its sound processing the moment it
answers the identity query, and installs the package of its model, reusing the
installer page's rescue path through a new Updater.rescueWithin in docs/pxota.js.
Bounded by --timeout (default 180 s); an install that has started is never cut short.
Tested against a simulated pedal with a restart loop.
POST /api/down/NAME and /api/up/NAME drive a button through the 800, 700
and 350 ms of firmware/openpocket.c, so a client can press, hold and
release instead of naming a gesture. The state reports held buttons and
PARA's detents. A hold of HOME no longer leaves the tuner, as on the
pedal. / and /plain routes are added for the pedal skin.
tools/sim/pedal.html draws the BlackBox panel in code and works as a
control surface: buttons, footswitches and both knobs by mouse, touch
and keyboard, with the live screen in the LCD and backlights that follow
the state. tools/sim/pedal-input.js holds the input mapping, which runs
in Node. The earlier page moves to /plain.

The panel's TUNER line is the stock firmware's. OpenPocket opens the
tuner with a long press of HOME, so two footswitches stay two presses.
Cut with prepare.py, which records the source and loop points of each.
The manifest and ATTRIBUTION.md carry the licence, source and checksum.
engine/px_wasm.c mirrors dsp_block() of the firmware, so the same engine
and math library run in a browser. The binary is committed, because the
simulator needs only a C compiler; node tools/op.mjs wasm rebuilds it in
the container. render.mjs renders the bundled loops to WAV files.
The Sound section plays a loop, a file or a computer input through the
engine in an AudioWorklet. The engine follows the preset on the screen,
MASTER and a new bypass, and the page reports the measured load to the
status text. A device starts muted. tests/test_audio.mjs checks the
engine on known signals and against the native build, and
tests/test_audio_page.mjs drives the section in Chromium.
@isod89
isod89 merged commit 81d10b6 into isod89:main Nov 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants