Editor: fix firmware push stall - small chunks + send only to the Pico
Trace showed the push reaching "pushing" then stalling. Two causes: (1) _send went to ALL MIDI outputs incl. "Midi Through Port-0" (a loopback that just echoes back); (2) the 512-char chunks overran the Pico's USB-MIDI receive buffer, so the device never saw the end of a chunk's SysEx and never ACKed. - _send now targets only the device port (name match pico/circuitpython/usb_midi; falls back to all outputs if none match) - no loopback echo. - Firmware chunks 512 -> 64 base64 chars (a SysEx that fits the RX buffer); log progress every 50 chunks + a "committing" line so the console shows it advancing. Editor-only; hard-reload to pick it up (no firmware change). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c5cc329185
commit
937e7c332d
1 changed files with 12 additions and 6 deletions
18
editor.html
18
editor.html
|
|
@ -1147,7 +1147,11 @@ async function loadFromDevice() {
|
||||||
let _midiAccess = null, _midiOn = false, _midiFlash = 0, _midiBeat = 0, _saveCb = null, _verCb = null;
|
let _midiAccess = null, _midiOn = false, _midiFlash = 0, _midiBeat = 0, _saveCb = null, _verCb = null;
|
||||||
function _midiInputs() { return _midiAccess ? [..._midiAccess.inputs.values()] : []; }
|
function _midiInputs() { return _midiAccess ? [..._midiAccess.inputs.values()] : []; }
|
||||||
function _midiOutputs() { return _midiAccess ? [..._midiAccess.outputs.values()] : []; }
|
function _midiOutputs() { return _midiAccess ? [..._midiAccess.outputs.values()] : []; }
|
||||||
function _send(bytes) { for (const o of _midiOutputs()) { try { o.send(bytes); } catch (_) {} } }
|
function _isDevicePort(p) { const n = (p.name || "").toLowerCase(); return n.includes("pico") || n.includes("circuitpython") || n.includes("usb_midi"); }
|
||||||
|
function _send(bytes) { // send only to the PM_K-1 (not loopback ports like "Midi Through", which just echo)
|
||||||
|
const outs = _midiOutputs(), dev = outs.filter(_isDevicePort);
|
||||||
|
for (const o of (dev.length ? dev : outs)) { try { o.send(bytes); } catch (_) {} }
|
||||||
|
}
|
||||||
function _clockSysex() { const d = new Date(); // F0 7D 01 yr-2000 mo dd hh mm ss F7 -> sets the device RTC
|
function _clockSysex() { const d = new Date(); // F0 7D 01 yr-2000 mo dd hh mm ss F7 -> sets the device RTC
|
||||||
return [0xF0, 0x7D, 0x01, d.getFullYear() - 2000, d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), 0xF7]; }
|
return [0xF0, 0x7D, 0x01, d.getFullYear() - 2000, d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), 0xF7]; }
|
||||||
async function _ensureMidi() { // MIDI access WITH SysEx (needed to send/receive SysEx); cached
|
async function _ensureMidi() { // MIDI access WITH SysEx (needed to send/receive SysEx); cached
|
||||||
|
|
@ -1245,20 +1249,22 @@ function _ack(timeout) {
|
||||||
return new Promise((res) => { _saveCb = res; setTimeout(() => { if (_saveCb) { _saveCb = null; res(null); } }, timeout); });
|
return new Promise((res) => { _saveCb = res; setTimeout(() => { if (_saveCb) { _saveCb = null; res(null); } }, timeout); });
|
||||||
}
|
}
|
||||||
function _b64(u8) { let s = ""; for (let i = 0; i < u8.length; i++) s += String.fromCharCode(u8[i]); return btoa(s); }
|
function _b64(u8) { let s = ""; for (let i = 0; i < u8.length; i++) s += String.fromCharCode(u8[i]); return btoa(s); }
|
||||||
// Push the base64-encoded .mpy in flow-controlled chunks (512 base64 chars = a multiple of 4, so each
|
// Push the base64-encoded .mpy in small, flow-controlled chunks: begin(0x21) -> data(0x22)* -> commit(0x23),
|
||||||
// decodes cleanly on the device): begin(0x21) -> data(0x22)* -> commit(0x23), waiting for each ACK. The
|
// waiting for each ACK. The device base64-decodes each chunk to /app.new, verifies the .mpy header, then
|
||||||
// device base64-decodes each chunk to /app.new, verifies the .mpy header, then A/B-installs + reboots.
|
// A/B-installs + reboots. CH is small (and a multiple of 4) so a chunk fits the Pico's USB-MIDI RX buffer.
|
||||||
async function _pushFirmware(b64) {
|
async function _pushFirmware(b64) {
|
||||||
_send([0xF0, 0x7D, 0x21, 0xF7]);
|
_send([0xF0, 0x7D, 0x21, 0xF7]);
|
||||||
if (await _ack(3000) !== true) return "handshake";
|
if (await _ack(3000) !== true) return "handshake";
|
||||||
const CH = 512;
|
const CH = 64, total = Math.ceil(b64.length / CH); let done = 0;
|
||||||
for (let o = 0; o < b64.length; o += CH) {
|
for (let o = 0; o < b64.length; o += CH) {
|
||||||
const part = b64.slice(o, o + CH); const msg = [0xF0, 0x7D, 0x22];
|
const part = b64.slice(o, o + CH); const msg = [0xF0, 0x7D, 0x22];
|
||||||
for (let i = 0; i < part.length; i++) msg.push(part.charCodeAt(i)); // base64 is ASCII
|
for (let i = 0; i < part.length; i++) msg.push(part.charCodeAt(i)); // base64 is ASCII
|
||||||
msg.push(0xF7); _send(msg);
|
msg.push(0xF7); _send(msg);
|
||||||
const a = await _ack(4000);
|
const a = await _ack(4000);
|
||||||
if (a !== true) return "transfer at " + o + "/" + b64.length + (a === false ? " (rejected)" : " (timeout)");
|
if (a !== true) return "chunk " + (done + 1) + "/" + total + (a === false ? " rejected" : " no-ack");
|
||||||
|
if (++done % 50 === 0) console.log("[fw] pushed", done, "/", total, "chunks");
|
||||||
}
|
}
|
||||||
|
console.log("[fw] all", total, "chunks sent; committing...");
|
||||||
_send([0xF0, 0x7D, 0x23, 0xF7]);
|
_send([0xF0, 0x7D, 0x23, 0xF7]);
|
||||||
return (await _ack(6000)) === true ? null : "verify";
|
return (await _ack(6000)) === true ? null : "verify";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue