Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions arena_studio.html
Original file line number Diff line number Diff line change
Expand Up @@ -2917,7 +2917,7 @@ <h2 id="modalTitle">Import error</h2>
</div>

<footer id="footer">
<span class="foot-left">Arena Studio v0.67 | 2026-07-21 16:25 ET · <a href="https://github.com/reiserlab/webDisplayTools" target="_blank" rel="noopener" title="webDisplayTools on GitHub source, issues, and release notes (docs/development/arena-studio-release-notes.md)">GitHub</a></span>
<span class="foot-left">Arena Studio v0.69 | 2026-07-21 16:46 ET · <a href="https://github.com/reiserlab/webDisplayTools" target="_blank" rel="noopener" title="webDisplayTools on GitHub: source, issues, and release notes (docs/development/arena-studio-release-notes.md)">GitHub</a></span>
<!-- Course-repo quick-links: open protocols / logs / patterns in a new tab.
Hrefs built from the configured repo + bench id (updateGhQuickLinks). -->
<span id="ghQuickLinks" title="Open the course repo on GitHub (new tab)">
Expand Down Expand Up @@ -7201,16 +7201,18 @@ <h2 id="modalTitle">Import error</h2>
renderIspReport(states);
await pushIspStatus(states);

// Flash with one retry on timeout/failure.
// Flash with up to two retries on timeout/failure. The controller
// jitters its receipt-poll cadence between attempts, so a retry
// genuinely re-rolls timing races instead of replaying them.
let flashed = false, lastMsg = '';
for (let attempt = 1; attempt <= 2 && !flashed; attempt++) {
if (attempt === 2) {
st.detail = 'retry…';
for (let attempt = 1; attempt <= 3 && !flashed; attempt++) {
if (attempt > 1) {
st.detail = 'retry ' + (attempt - 1) + '…';
renderIspReport(states);
await ispSleep(400);
}
const r = await ispSend(
'g6-program-panel ' + panel + (attempt === 2 ? ' (retry)' : ''),
'g6-program-panel ' + panel + (attempt > 1 ? ' (retry ' + (attempt - 1) + ')' : ''),
Wire.encodeG6ProgramPanel(panel), Wire.OPCODES.G6_PROGRAM_PANEL, 240000);
if (r.ok) { flashed = true; lastMsg = r.message; }
else lastMsg = r.message || (r.timeout ? 'timeout' : 'error');
Expand Down Expand Up @@ -7245,8 +7247,13 @@ <h2 id="modalTitle">Import error</h2>
$('cIspStopBtn').disabled = true;
if (Studio.session.connected) $('cIspBtn').disabled = false;
$('cIspCopyBtn').style.display = '';
const summary = 'Done: ' + nVerified + ' verified, ' + nFlashed + ' flashed, ' +
nBad + ' failed/skipped of ' + panels.length + (isp.abort ? ' (stopped)' : '');
// nVerified and nFlashed are mutually exclusive (verified = flashed AND
// CRC-matched; flashed = flashed with verify off/unavailable), so lead
// with the total a human wants and break the rest down.
const nOk = nVerified + nFlashed;
const summary = 'Done: ' + nOk + '/' + panels.length + ' flashed (' +
nVerified + ' verified, ' + nFlashed + ' unverified, ' +
nBad + ' failed/skipped)' + (isp.abort ? ' (stopped)' : '');
$('cIspStatus').textContent = summary;
const sum = $('cFwSum');
if (sum) sum.textContent = 'flash · verify · batch';
Expand Down
21 changes: 14 additions & 7 deletions docs/development/arena-studio-isp-firmware-push-handoff.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,21 @@ a release tag land. Entries with no `uf2` key are ISP-only (no UF2 staged).
local `crc32(bytes)` before proceeding. Long transfer (~140 KB); generous timeout.
2. **(Optional) confirm what's on SD:** `encodeGetFirmwareInfo()` → `0xE3`; `decodeFirmwareInfo()`
returns `{magic, version, imageCrc32, imageSize}` — `version` is the release tag. Great UI field.
3. **Per panel:** `encodeG6ProgramPanel(n)` → `0xC8` (1-based index). Long-running (stage ~540
pages over SPI + LittleFS commit + reboot ≈ 30–45 s); `decodeProgramPanelResponse()` gives
`{ok, status, message}` with the controller's step-by-step failure text.
3. **Per panel:** `encodeG6ProgramPanel(n)` → `0xC8` (1-based index). Long-running: the
controller stages ~540 pages over SPI, then POLLS the panel's commit receipt (15 s ceiling)
and post-reboot liveness (12 s ceiling) instead of fixed waits, so it returns as soon as the
panel is back up (~3.2 s typical, fleet-validated; ceilings bound the worst case).
`decodeProgramPanelResponse()` gives `{ok, status, message}` with the
controller's step-by-step failure text; the success message now carries a per-phase timing
summary.
4. **Verify:** `encodeG6VerifyPanel(n)` → `0xC9` — CRCs the panel's live app flash against the SD
footer. `MATCH` = that exact release is installed. Non-destructive; also useful as a fleet
"which version is everyone running?" audit loop.
5. **What the human sees** (with the progress-indicator firmware running on the target): progress
bar sweeps during staging → brief dark at commit/reboot → **smiley** held until the first real
display frame arrives. Failed panels: no smiley.
5. **What the human sees** (with the progress-indicator firmware running on the target): one
weighted bar spans the visible process: upload sweeps columns 0-16, verify lights 17, the
LittleFS commit animates 17-20 (full bar = staged, reboot imminent) → dark during the OTA
copy → **smiley** held until the first real display frame arrives. Failed panels: **sad
smiley** on a failed commit, or no smiley after the dark window.

**Reference implementation that ran the real fleet reflash (2026-07-02):** the Python tool
`isp_roundtrip.py` (firmware-session scratchpad; mirrors this exact flow with response-frame
Expand All @@ -82,7 +88,8 @@ timeout, always verify after program.
(require MATCH)} with a stop-on-failure toggle; show the controller's `message` text verbatim.
- Show SD-card state (`0xE3` footer version) persistently — "arena is loaded with panel-fw-v1.0.0".
- Sequential only — one `0xC8` at a time (the controller ISPs one panel per command).
- Expect the target panel to drop off/reboot ~30–45 s after program; verify only after it settles.
- The controller now polls the panel back to life before answering `0xC8`, so a success response
means the panel already rebooted and is answering COMM_CHECK; verify right after.

## 6. Gotchas

Expand Down
16 changes: 16 additions & 0 deletions docs/development/arena-studio-release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ The Studio's footer used to carry the full changelog inline; it now shows one li
history lives here. Newest first. (Per-session engineering detail stays in
`arena-studio-handover.md` and the design docs — this file is the user-facing what-changed list.)

## v0.69 (2026-07-21) · ISP batch retries a failed panel twice

- **A failed panel flash now gets up to two retries** (was one) before being
marked failed/skipped, with the attempt number shown in the log and report
("retry 1", "retry 2"). Paired with a controller-firmware change that
varies its receipt-poll timing between attempts, so a retry re-rolls
timing-related failures instead of replaying them exactly.

## v0.68 (2026-07-21) · Clearer ISP batch summary

- **The ISP batch summary now leads with the total.** A run where every panel
flashed and CRC-verified used to end with "20 verified, 0 flashed, 0
failed/skipped of 20", which read as if nothing had been flashed ("flashed"
meant flashed-without-verify). It now reads "Done: 20/20 flashed (20
verified, 0 unverified, 0 failed/skipped)".

## v0.67 — 2026-07-21 · Console picker previews any connected SD-card pattern

- **The Console pattern picker now shows a thumbnail for patterns already on
Expand Down
2 changes: 1 addition & 1 deletion tests/test-arena-studio-alt.js
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ check(
alt.includes("const ALT_BUILD_STAMP = '2026-07-13 18:55 ET';") &&
alt.includes("stampNode.nodeValue = ALT_TOOL_VERSION + ' | ' + ALT_BUILD_STAMP + ' · ';") &&
alt.includes('Studio.TOOL_VERSION = ALT_TOOL_VERSION;') &&
studio.includes('Arena Studio v0.67 | 2026-07-21 16:25 ET')
studio.includes('Arena Studio v0.69 | 2026-07-21 16:46 ET')
);

console.log('=== scoped presentation ===');
Expand Down
Loading