From 9e0cf1211892d3f0f6fbe3d979f07ed0599f53cc Mon Sep 17 00:00:00 2001 From: agent Date: Wed, 29 Jul 2026 03:45:45 +0000 Subject: [PATCH] =?UTF-8?q?fix(bridge):=20build=2010=E2=80=94=E2=80=94?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=A0=81=208/16=20=E6=8C=89=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E4=BF=A1=E6=81=AF=E7=A0=81=E5=A4=84=E7=90=86=EF=BC=88?= =?UTF-8?q?=E5=9B=BA=E4=BB=B6=E5=8F=8D=E6=B1=87=E7=BC=96=E5=AE=9E=E8=AF=81?= =?UTF-8?q?=EF=BC=9AMEM=5FDEV=20type=20=E6=A3=80=E6=9F=A5=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=EF=BC=89+=20=E9=98=B6=E6=AE=B5=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=8F=96=E8=AF=81=20+=20SPOTA=20=E5=86=99=E7=89=B9=E5=BE=81?= =?UTF-8?q?=E5=85=A5=20CHARS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/bridge_server.py | 45 +++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tools/bridge_server.py b/tools/bridge_server.py index 9fe5d87..61f5c00 100644 --- a/tools/bridge_server.py +++ b/tools/bridge_server.py @@ -27,7 +27,7 @@ import platform import sys PROTOCOL_VERSION = 1 -SERVER_BUILD = 9 # 2026-07-29: StreamReader limit 64KiB→4MiB(OTA 144KB 请求行根因修复) +SERVER_BUILD = 10 # 2026-07-29: 状态码 8/16 按会话信息码处理(固件反汇编实证)+ 阶段状态取证 + SPOTA 写特征入 CHARS EPD_SERVICE_UUID = "13187b10-eba9-a3ba-044e-83d3217d9a38" EPD_CHAR_UUID = "4b646063-6264-f3a7-8941-e65356ea82fe" @@ -56,7 +56,11 @@ CHARS = {"epd": EPD_CHAR_UUID, "rxtx": RXTX_CHAR_UUID, "alt": ALT_NOTIFY_UUID, "dis_model": "00002a24-0000-1000-8000-00805f9b34fb", "dis_fw": "00002a26-0000-1000-8000-00805f9b34fb", "spota_mem_info": "6c53db25-47a1-45fe-a022-7c92fb334fd4", - "spota_status_ro": "64b4e8b5-0de5-401b-a21d-acc8db3b913a"} + "spota_status_ro": "64b4e8b5-0de5-401b-a21d-acc8db3b913a", + "spota_mem_dev": "8082caa8-41a6-4021-91c6-56f9b954cc34", + "spota_gpio": "724249f0-5ec3-4b5f-8804-42345af08651", + "spota_patch_len": "9d84b9a3-000c-49d8-9183-855b673fda31", + "spota_patch_data": "457871e8-d516-4ca1-9116-57d0b17b9cb2"} # 实机 GATT(2026-07-28 bridge 诊断):1f1f(h=53)=仅write 无 notify; # 331f(h=57)=notify+write+read,为真交互通道;EPD(h=48)=notify+write @@ -155,11 +159,6 @@ class BleSession: def _on_status(_s, data: bytearray): status_q.put_nowait(int.from_bytes(bytes(data), "little")) - async def wait_ok(what: str): - status = await asyncio.wait_for(status_q.get(), status_timeout) - if status != STATUS_OK: - raise RuntimeError(f"{what} 失败: 状态码 {status}") - acc = 0 for b in image: acc ^= b @@ -170,24 +169,52 @@ class BleSession: await asyncio.wait_for( self.client.write_gatt_char(char, data, response=True), to) + async def drain(label: str, settle: float = 0.5): + """排干状态队列并如实上报(阶段状态码取证)。""" + await asyncio.sleep(settle) + got = [] + while not status_q.empty(): + got.append(status_q.get_nowait()) + if got: + yield {"event": "ota_stage", "stage": f"{label}_status", "codes": got} + await asyncio.wait_for( self.client.start_notify(SPOTA_SERV_STATUS_UUID, _on_status), 10) try: await w(SPOTA_MEM_DEV_UUID, MEM_DEV_SPI_FLASH) yield {"event": "ota_stage", "stage": "mem_dev_ok"} + async for ev in drain("mem_dev", 1.0): + yield ev await w(SPOTA_GPIO_MAP_UUID, GPIO_MAP_DEFAULT) yield {"event": "ota_stage", "stage": "gpio_map_ok"} + async for ev in drain("gpio_map", 1.0): + yield ev for idx, block in enumerate(blocks, 1): await w(SPOTA_PATCH_LEN_UUID, len(block).to_bytes(2, "little")) for i in range(0, len(block), WRITE_CHUNK): await self.client.write_gatt_char(SPOTA_PATCH_DATA_UUID, block[i:i + WRITE_CHUNK], response=False) yield {"event": "ota_block_sent", "block": idx, "total": len(blocks)} - await wait_ok(f"块 {idx}/{len(blocks)}") + # 块确认:只认 2;8/16 为会话信息码(固件 0x07FCB770/0x07FCB780 证据),记录并跳过 + while True: + status = await asyncio.wait_for(status_q.get(), status_timeout) + if status == STATUS_OK: + break + if status in (8, 16): + yield {"event": "ota_stage", "stage": f"block{idx}_info_status", "codes": [status]} + continue + raise RuntimeError(f"块 {idx}/{len(blocks)} 失败: 状态码 {status}") yield {"event": "ota_progress", "block": idx, "total": len(blocks)} await w(SPOTA_MEM_DEV_UUID, END_SIGNAL) yield {"event": "ota_stage", "stage": "end_signal_ok"} - await wait_ok("镜像校验") + while True: + status = await asyncio.wait_for(status_q.get(), status_timeout) + if status == STATUS_OK: + break + if status in (8, 16): + yield {"event": "ota_stage", "stage": "end_info_status", "codes": [status]} + continue + raise RuntimeError(f"镜像校验 失败: 状态码 {status}") await w(SPOTA_MEM_DEV_UUID, REBOOT_SIGNAL) yield {"event": "ota_stage", "stage": "reboot_sent"} finally: