Skip to content

Commit 3430c6a

Browse files
widgetiiclaude
andauthored
agent: bump client.crc32 timeout for V1-era SoCs (#98)
## Summary `client.crc32()`'s timeout formula `max(10, 5 + size_MiB)` is too aggressive for V1-era HiSilicon SoCs (hi3520dv200 / HISFC350 controller) where the agent walks flash via the AHB STD READ window at ~150 KB/s. A 4 MiB CRC32 needed ~27 s on hi3520dv200 but the host bailed at 10 s and reported "No packet received within 10s" — misleading: the device kept computing and the response was already in flight. New formula: `max(15, 5 + size / (100 * 1024))` — assumes 100 KB/s of effective throughput (safe under the slow V1 path) with a 15 s baseline. V3+/V4+ DMA reads at multi-MB/s still complete well under the ceiling. ## Why this matters Caught after a real install on hi3520dv200: a relocation script crashed at the 10 s CRC timeout, forcing me to split the operation into two scripts. The second script's "erase old location" then wiped 2.74 MiB of the freshly-written-and-verified rootfs because it didn't subtract the new write's footprint — see [OpenIPC/firmware#2089 (closed)](OpenIPC/firmware#2089) for the full incident write-up. The bug was operator-level (not in defib's blessed `install` flow), but the too-tight CRC timeout was the contributing factor that drove me to the staged-script approach where the overlap mistake became easy to make. Fixing this is the minimum-viable defib change that would have averted the chain. ## Test plan - [x] All 490 Python tests pass (`uv run pytest tests/ -x -q --ignore=tests/fuzz`) - [x] ruff + mypy clean - [x] Verified on real hi3520dv200 hardware: 3.74 MiB CRC completes in ~25 s and matches the source CRC32 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Dmitry Ilyin <widgetii@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b07ce50 commit 3430c6a

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

src/defib/agent/client.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,15 @@ async def crc32(self, addr: int, size: int) -> int:
585585

586586
payload = struct.pack("<II", addr, size)
587587
await send_packet(self._transport, CMD_CRC32, payload)
588-
timeout = max(10.0, 5.0 + size / (1024 * 1024))
588+
# AHB STD READ on V1-era SoCs (hi3520dv200 / HISFC350) tops out at
589+
# ~150 KB/s when the agent walks flash via the memory-mapped window,
590+
# so a 4 MiB CRC takes ~27 s. The old `5 + size/MiB` formula timed
591+
# out at 10 s for anything under ~5 MiB and led to misdiagnosed
592+
# "agent stopped responding" failures even though the device was
593+
# still computing the CRC and the response was on its way.
594+
# Assume a conservative 100 KB/s and a 15 s baseline so V3+/V4+
595+
# chips (DMA reads, multi-MB/s) still get plenty of headroom.
596+
timeout = max(15.0, 5.0 + size / (100 * 1024))
589597
cmd, data = await recv_response(self._transport, timeout=timeout)
590598
if cmd != RSP_CRC32 or len(data) < 4:
591599
raise RuntimeError("CRC32 response invalid")

0 commit comments

Comments
 (0)