From 94fea411a9fddfa9a146e028ca56f6d3b4818c3c Mon Sep 17 00:00:00 2001 From: agent Date: Wed, 29 Jul 2026 04:56:12 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20SUOTA=20=E7=8A=B6=E6=80=81=E7=A0=81?= =?UTF-8?q?=E5=88=86=E5=B1=82=E4=B8=8E=200x38000=20=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E5=A4=B4=E9=98=BB=E6=96=AD=E6=A0=B9=E5=9B=A0=E5=85=A5=20DECISI?= =?UTF-8?q?ONS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DECISIONS.md | 3 +++ tools/gpio_probe.py | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index d7aa5c9..b283712 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -17,3 +17,6 @@ | 2026-07-28 | 设备睡眠行为适配:广播窗口短(约 30-60s),连接态保持清醒 | 实测:空闲即停广播;单连接 batch 可在窗口内跑完全部命令 | 现场测试统一用 `ppclock batch` 单连接;唤醒守候循环(每 15-20s 重试)跨窗口执行 | | 2026-07-29 | **SUOTA 状态码 8/16 = 会话信息码而非失败**(仅本固件) | 反汇编 MEM_DEV handler(0x07FCB6F8):type 0x13 命中 bit4 位测试 → 发状态 16 且 SPOTA 状态保持(0x07FCB770-0x07fcb772);type 0x12 → 状态 8 并清会话(0x07FCB780);空镜像探针与正式烧录均先收 16 后流程完好 | bridge ota 对 8/16 记录并继续,块确认只认 2;APK 错误表未覆盖 16,以固件证据为准 | | 2026-07-29 | bridge OTA 大请求需显式 StreamReader limit | asyncio 默认 64KiB 行限制,OTA 镜像 hex 请求 ~144KB 永不可达(三轮"静默停滞"根因);空镜像探针 0.6s 全通证明管线无恙 | build 9: start_server(limit=4MiB);教训:大载荷 RPC 协议设计必须考虑传输层帧限 | +| 2026-07-29 | **SUOTA 状态码分两类:会话信息码(8/16)与流程错误码**;16=MEM_DEV type 0x13 位测试应答(固件 0x07FCB770),状态保持 | 反汇编 MEM_DEV handler + 三轮烧录对照(16 恒在 MEM_DEV 后 ~1s 到达,块未受影响) | bridge 对 8/16 记录继续、块确认只认 2;APK 表未覆盖 16,固件证据为准 | +| 2026-07-29 | **SUOTA 状态 22/20 根因分层**:22=0x38000 产品头读电气失败(GPIO_MAP 引脚错);20=读成功但非 'pR'(引脚有效、0x38000 疑为空) | GPIO 探针(max_blocks=2 安全模式):A{00,00,06,05}→22、B{40,00,06,05}→22、C{05,06,00,40}→20;C=APK 整数 0x05060040 的 BE 字节,为唯一电气有效候选 | GPIO_MAP 采用 C(BE 序);剩余阻断=0x38000 产品头('pR')缺失/无效,见下条 | +| 2026-07-29 | **0x38000 产品头阻断为 vendor 级问题**:固件在首 0x200 缓冲处理时校验 0x38000 的 'pR' 产品头(0x07FCB4AA),无效则发 20 并中止该缓冲处理;本机疑以裸 'pQ' 直启(无产品头) | 反汇编完整校验链;固件镜像内 0x3A19 处的 70 52 系代码巧合非真产品头;MEM_INFO 读回 00000000 | 强推 END 有变砖风险(END 会写 0xAA 标志+复位,裸启兜底可恢复但需 JTAG 兜底方案);暂缓强推,先与用户决策 | diff --git a/tools/gpio_probe.py b/tools/gpio_probe.py index 6412f45..68833ad 100644 --- a/tools/gpio_probe.py +++ b/tools/gpio_probe.py @@ -26,16 +26,20 @@ class Bridge: self.next_id = 0 async def open(self): + try: + self.w.close() + except Exception: + pass self.r, self.w = await asyncio.open_connection(HOST, PORT) - async def rpc(self, op, timeout=120, **kw): + async def rpc(self, op, wait=120, **kw): self.next_id += 1 rid = self.next_id self.w.write(json.dumps({"id": rid, "op": op, **kw}).encode() + b"\n") await self.w.drain() events = [] while True: - line = await asyncio.wait_for(self.r.readline(), timeout) + line = await asyncio.wait_for(self.r.readline(), wait) if not line: raise ConnectionError("bridge EOF") msg = json.loads(line) @@ -46,8 +50,13 @@ class Bridge: async def connect_until_awake(self, tries=12): for i in range(tries): - resp, _ = await self.rpc("connect", 150, address=DEVICE, - timeout=30, subscribe=False) + try: + resp, _ = await self.rpc("connect", 150, address=DEVICE, + timeout=30, subscribe=False) + except (ConnectionError, asyncio.TimeoutError): + print(" 连接通道中断,重开 TCP...") + await self.open() + continue if resp.get("ok"): print(f"连接成功(第 {i + 1} 次)") return True