Push reliability: 10s ACK timeout + per-chunk flush + periodic GC
Push to 0.0.14 stalls at ~150 chunks with the MIDI badge going gray (=device silent for >1s). It's an occasional slow flash flush on the device side — the file buffer fills, flush takes several seconds, the editor's 4s timeout cuts it off too early. - Editor: bump per-chunk ACK timeout 4s -> 10s; progress log every 25 chunks now with elapsed seconds so you can see it advancing through a slow chunk. - Device 0.0.14: flush per chunk (small, predictable per-chunk cost instead of infrequent multi-second bursts) + gc.collect() every 50 chunks to keep the heap fresh during a long push. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
99174d1bf8
commit
f637a65abd
3 changed files with 17 additions and 8 deletions
15
editor.html
15
editor.html
|
|
@ -1256,19 +1256,24 @@ function _b64(u8) { let s = ""; for (let i = 0; i < u8.length; i++) s += String.
|
|||
// 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) {
|
||||
_send([0xF0, 0x7D, 0x21, 0xF7]);
|
||||
if (await _ack(3000) !== true) return "handshake";
|
||||
if (await _ack(5000) !== true) return "handshake";
|
||||
const CH = 64, total = Math.ceil(b64.length / CH); let done = 0;
|
||||
const t0 = Date.now();
|
||||
for (let o = 0; o < b64.length; o += CH) {
|
||||
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
|
||||
msg.push(0xF7); _send(msg);
|
||||
const a = await _ack(4000);
|
||||
// Generous per-chunk timeout: an occasional flash flush on the device can take several seconds.
|
||||
const a = await _ack(10000);
|
||||
if (a !== true) return "chunk " + (done + 1) + "/" + total + (a === false ? " rejected" : " no-ack");
|
||||
if (++done % 50 === 0) console.log("[fw] pushed", done, "/", total, "chunks");
|
||||
if (++done % 25 === 0) {
|
||||
const el = ((Date.now() - t0) / 1000).toFixed(1);
|
||||
console.log("[fw] pushed " + done + " / " + total + " chunks (" + el + " s)");
|
||||
}
|
||||
}
|
||||
console.log("[fw] all", total, "chunks sent; committing...");
|
||||
console.log("[fw] all " + total + " chunks sent; committing...");
|
||||
_send([0xF0, 0x7D, 0x23, 0xF7]);
|
||||
return (await _ack(6000)) === true ? null : "verify";
|
||||
return (await _ack(10000)) === true ? null : "verify";
|
||||
}
|
||||
function _pickBinary() { // offline fallback: choose an app.mpy -> Uint8Array (or null if cancelled)
|
||||
return new Promise(async (res) => {
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -407,7 +407,7 @@ class App:
|
|||
self.midi_in = usb_midi.ports[0] if (MIDI_ENABLED and usb_midi and len(usb_midi.ports) > 0) else None
|
||||
self._mbuf = bytearray(64); self.midi_host = False; self.last_midi_in = 0.0
|
||||
self._sx = bytearray(); self._sxon = False # USB-MIDI SysEx assembler (clock + pushed programs)
|
||||
self._fw = None # chunked firmware transfer: staging file handle
|
||||
self._fw = None; self._fw_n = 0 # chunked firmware transfer: staging file handle + chunk counter
|
||||
self.led = RGB(P_RGB)
|
||||
self.spk = pwmio.PWMOut(P_SPK, frequency=1600, variable_frequency=True, duty_cycle=0)
|
||||
self.spk_off = 0
|
||||
|
|
@ -1088,13 +1088,17 @@ class App:
|
|||
try:
|
||||
try: self._fw.close()
|
||||
except Exception: pass
|
||||
self._fw = open("/app.new", "wb"); self._ack(True)
|
||||
self._fw = open("/app.new", "wb"); self._fw_n = 0; self._ack(True)
|
||||
except Exception: # read-only (editor mode) / no space
|
||||
self._fw = None; self._ack(False)
|
||||
elif cmd == 0x22: # DATA: a base64 chunk (multiple of 4) -> decode -> append
|
||||
try:
|
||||
if self._fw is None or a2b_base64 is None: raise OSError()
|
||||
self._fw.write(a2b_base64(bytes(sx[2:]))); self._ack(True)
|
||||
self._fw.write(a2b_base64(bytes(sx[2:])))
|
||||
self._fw.flush() # small, predictable per-chunk flush (no slow burst flushes later)
|
||||
self._fw_n += 1
|
||||
if self._fw_n % 50 == 0: gc.collect() # keep the heap fresh during a long push
|
||||
self._ack(True)
|
||||
except Exception:
|
||||
try: self._fw.close()
|
||||
except Exception: pass
|
||||
|
|
|
|||
Loading…
Reference in a new issue