fix(bridge): build 10——状态码 8/16 按会话信息码处理(固件反汇编实证:MEM_DEV type 检查路径)+ 阶段状态取证 + SPOTA 写特征入 CHARS
This commit is contained in:
1 parent
34adaf4b81
commit
9e0cf12118
1 file changed
+36
-9
+36
-9
@@ -27,7 +27,7 @@ import platform
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
PROTOCOL_VERSION = 1
|
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_SERVICE_UUID = "13187b10-eba9-a3ba-044e-83d3217d9a38"
|
||||||
EPD_CHAR_UUID = "4b646063-6264-f3a7-8941-e65356ea82fe"
|
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_model": "00002a24-0000-1000-8000-00805f9b34fb",
|
||||||
"dis_fw": "00002a26-0000-1000-8000-00805f9b34fb",
|
"dis_fw": "00002a26-0000-1000-8000-00805f9b34fb",
|
||||||
"spota_mem_info": "6c53db25-47a1-45fe-a022-7c92fb334fd4",
|
"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;
|
# 实机 GATT(2026-07-28 bridge 诊断):1f1f(h=53)=仅write 无 notify;
|
||||||
# 331f(h=57)=notify+write+read,为真交互通道;EPD(h=48)=notify+write
|
# 331f(h=57)=notify+write+read,为真交互通道;EPD(h=48)=notify+write
|
||||||
|
|
||||||
@@ -155,11 +159,6 @@ class BleSession:
|
|||||||
def _on_status(_s, data: bytearray):
|
def _on_status(_s, data: bytearray):
|
||||||
status_q.put_nowait(int.from_bytes(bytes(data), "little"))
|
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
|
acc = 0
|
||||||
for b in image:
|
for b in image:
|
||||||
acc ^= b
|
acc ^= b
|
||||||
@@ -170,24 +169,52 @@ class BleSession:
|
|||||||
await asyncio.wait_for(
|
await asyncio.wait_for(
|
||||||
self.client.write_gatt_char(char, data, response=True), to)
|
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(
|
await asyncio.wait_for(
|
||||||
self.client.start_notify(SPOTA_SERV_STATUS_UUID, _on_status), 10)
|
self.client.start_notify(SPOTA_SERV_STATUS_UUID, _on_status), 10)
|
||||||
try:
|
try:
|
||||||
await w(SPOTA_MEM_DEV_UUID, MEM_DEV_SPI_FLASH)
|
await w(SPOTA_MEM_DEV_UUID, MEM_DEV_SPI_FLASH)
|
||||||
yield {"event": "ota_stage", "stage": "mem_dev_ok"}
|
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)
|
await w(SPOTA_GPIO_MAP_UUID, GPIO_MAP_DEFAULT)
|
||||||
yield {"event": "ota_stage", "stage": "gpio_map_ok"}
|
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):
|
for idx, block in enumerate(blocks, 1):
|
||||||
await w(SPOTA_PATCH_LEN_UUID, len(block).to_bytes(2, "little"))
|
await w(SPOTA_PATCH_LEN_UUID, len(block).to_bytes(2, "little"))
|
||||||
for i in range(0, len(block), WRITE_CHUNK):
|
for i in range(0, len(block), WRITE_CHUNK):
|
||||||
await self.client.write_gatt_char(SPOTA_PATCH_DATA_UUID,
|
await self.client.write_gatt_char(SPOTA_PATCH_DATA_UUID,
|
||||||
block[i:i + WRITE_CHUNK], response=False)
|
block[i:i + WRITE_CHUNK], response=False)
|
||||||
yield {"event": "ota_block_sent", "block": idx, "total": len(blocks)}
|
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)}
|
yield {"event": "ota_progress", "block": idx, "total": len(blocks)}
|
||||||
await w(SPOTA_MEM_DEV_UUID, END_SIGNAL)
|
await w(SPOTA_MEM_DEV_UUID, END_SIGNAL)
|
||||||
yield {"event": "ota_stage", "stage": "end_signal_ok"}
|
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)
|
await w(SPOTA_MEM_DEV_UUID, REBOOT_SIGNAL)
|
||||||
yield {"event": "ota_stage", "stage": "reboot_sent"}
|
yield {"event": "ota_stage", "stage": "reboot_sent"}
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Reference in new issue
Block a user