diff --git a/editor.html b/editor.html index c59e79f..7117e86 100644 --- a/editor.html +++ b/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) => { diff --git a/pico-cp/__pycache__/app.cpython-312.pyc b/pico-cp/__pycache__/app.cpython-312.pyc index c6a226a..f1ddf6e 100644 Binary files a/pico-cp/__pycache__/app.cpython-312.pyc and b/pico-cp/__pycache__/app.cpython-312.pyc differ diff --git a/pico-cp/app.py b/pico-cp/app.py index 2df5f11..8a923a2 100644 --- a/pico-cp/app.py +++ b/pico-cp/app.py @@ -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