fix(device-test): contain tool processes and add reviewed preview

This commit is contained in:
chenmingxuan committed 2026-10-30 12:43:36 +08:00
1 parent c98d7527a0
commit 7d31e09cb7
59 files changed
+23722

No files matched your search

@@ -0,0 +1,80 @@
# V1 搜索、查询与固件下发
本页摘记已实现接口;来源文件、修订及摘要见 [协议范围](protocol-support.md)。完整原文保留在资料提供方本地,分发包不附其他配置章节。实现在 `scripts/v1_protocol.py`,由适配器 `--protocol v1` 路由,不发送 V2 报文。
## 报文与端口
报文头共 8 字节:CMD、Length 各为网络字节序 U32,随后是恰好 Length 字节的 Data。长度按字节计算。只读 JSON 响应须为 UTF-8 对象;实现拒绝命令/长度不符、超过 1 MiB、错误类型及未完整接收的报文。
| 操作 | 传输 | 请求 | 返回 |
| --- | --- | --- | --- |
| 搜索 | 设备 UDP 4942,广播 | `0x5a0eff00`;JSON `{"session":1234}`,每次使用新的随机整数 | `0x5a0eff01`;同一整数 session,完整字符串 sn,以及 dev_type、ip、mac、firmware、hardware |
| 基本/固件信息 | 设备 TCP 4941 | `0x5a0e2104`;Length=0,无 Data;十六进制请求 `5a0e210400000000` | 同命令 JSON;整数 code=0 成功,其他值失败 |
| 固件升级 | 设备 TCP 4941 | `0x5a0e2170`;Data 为小写 ASCII MD5[32] + ROM,Length=32+ROM字节数 | 同命令、完整 JSON、整数 code=0;只确认协议应答,另行回读版本 |
TCP 查询处理报文分片,在连接/发送/接收阶段扣减同一时限,不自动重试。较新工厂文档建议查询 5 秒无响应超时,示例显式使用 `--timeout 5`。主机名解析及多地址尝试由系统 socket 负责,严格现场时限宜使用已确认的数字设备 IP。
广播接收绑定 `0.0.0.0:<client-port>`,默认 4942;请求从同一 socket 发到各选定 IPv4 网段的定向广播地址,目的端口 4942。默认枚举已启用物理网卡并排除回环/APIPA;可用 `--interface IPv4/PREFIX` 指定网段。相同网段只发一次,/31、/32 跳过。出接口服从 Windows 路由,特殊路由环境需现场核实。原文未规定客户端接收端口;默认 4942 是本机已验证的实现选择,`--client-port` 可调整,不能推广为所有固件的规范要求。
设备可能广播回复,因此接收 socket 不只绑定某个单播 IP。不启用端口复用、不结束占用进程;端口被占用时报告错误并释放本次 socket。忽略自身请求、错误 session/帧和非成功 code,精确筛选完整 SN/型号。按 SN、UDP 源 IP、MAC、型号去重;同 SN 出现冲突身份时阻断选择。后续连接使用实际 UDP 源 IP,报文中的 ip 只保留为观测。无响应只说明本轮未发现,不等于设备离线。
## 身份与版本字段
`2104` 保留文档字段 code、desc、sn、dev_type、firmware、hardware、dev_id、dev_ver。除整数 code 外均按字符串校验。如果设备额外直接上报 inner.version 或 outer.version 字符串,只保留该字面路径的版本值,供任务明确指定字段时观测;不保留其余未知字段。
| 字段 | 文档含义 | 用途 |
| --- | --- | --- |
| sn | 设备 SN | 与本次完整 SN 精确比较,不截尾、不去空格 |
| dev_type | 设备类型 | V1 `--expected-model` 唯一匹配字段 |
| dev_id | 设备 ID | 只保留,不代替型号 |
| firmware | 固件版本号 | 可由任务明确选择为原生固件验收字段 |
| dev_ver | 设备版本号 | 可由任务明确选择,不推断与 V2 字段的关系 |
| hardware | 硬件版本号 | 只观测,不作为固件验收 |
两份文档和 V1 查询源码没有 `firmware/dev_ver` 到 `inner.version/outer.version` 的对应关系。选择缺失的 outer.version 得到 `INCOMPLETE`,不会把 firmware 或 dev_ver 自动改名。如果设备直接上报所选字面路径,则可按该值比较。设备/文件名看起来可以猜出对应关系,也不能据此完成指定字段验收。
适配器用显式封套区分协议:
```json
{"protocol":"v1","cmd":1510875396,"code":0,"data":{"code":0,"sn":"<完整SN>","dev_type":"<型号>","firmware":"<版本>"}}
```
1510875396 是 `0x5a0e2104` 的十进制值。封套是适配器输出格式;线上 Data 是内部 JSON 本身。`verify-version --response` 接受此封套,或含 response 的完整 CLI 输出;不能使用 V2 30101 文件冒充 V1 响应。
## 调用示例
在技能目录执行,下列值均为占位符。型号未知时先 identify,只证明 SN 一致并观察型号,返回 model_verified=false;再带实测型号执行 info/预检。
```powershell
python scripts/device_adapter.py discover --protocol v1 --interface "<本机IPv4/前缀>" --expected-sn "<完整SN>" --timeout 5
python scripts/device_adapter.py identify --protocol v1 --host "<设备IP>" --expected-sn "<完整SN>" --timeout 5
python scripts/device_adapter.py info --protocol v1 --host "<设备IP>" --expected-sn "<完整SN>" --expected-model "<实测dev_type>" --timeout 5
python scripts/device_adapter.py upgrade --protocol v1 --host "<数字设备IP>" --expected-sn "<完整SN>" --expected-model "<实测dev_type>" --rom "<ROM路径>" --rom-sha256 "<64位SHA256>" --target-version "<目标版本>" --version-field firmware --timeout 5
python scripts/device_adapter.py upgrade --protocol v1 --host "<数字设备IP>" --expected-sn "<完整SN>" --expected-model "<实测dev_type>" --rom "<ROM路径>" --rom-sha256 "<审阅过的64位SHA256>" --target-version "<目标版本>" --version-field firmware --timeout 5 --execute
python scripts/device_adapter.py verify-version --protocol v1 --host "<设备IP>" --expected-sn "<完整SN>" --expected-model "<实测dev_type>" --target-version "<目标版本>" --version-field firmware --timeout 5
```
只有任务明确选择 firmware 时才使用示例字段;已有其他验收条件时保持原条件。V1 upgrade 默认返回 `PREFLIGHT_ONLY`,preflight_complete=true、write_supported=true、write_executed=false;selected_version_field_available 说明指定字段是否存在。当前任务已授权升级时,带审阅摘要及 `--execute` 才执行一次下发;不重复请求已给出的授权。
## 升级报文与完成含义
用户提供的 Qt 源码 `EpConnection::sendTcpFile` 补齐了文档第 21 节的空白 Data,线格式为:
```text
U32_BE 0x5a0e2170
U32_BE (32 + ROM字节数)
MD5_hex_ascii[32] # 全 ROM 的 MD5,小写十六进制文本;不是16字节原始摘要
ROM[ROM字节数]
```
总线上字节数为 ROM大小+40。没有 EPFP 前缀、文件名或自定义块头。源码使用约200 KiB块;TCP分块不改变线上字节序列,CLI采用256 KiB缓冲并处理部分send。不能把同一源码中的 `sendTcpFileV2(protocol=1)`(端口8940、EPFP/4001)混作此接口。
CLI 在完整 SN/dev_type 在线预检后重新验证 SHA-256。V1 发送器在同一个打开的文件上计算 MD5及SHA-256,核对大小/审阅摘要后才连接;回到文件开头发送,再对发送内容核对 SHA-256。Data长度必须适合 U32。总时限覆盖哈希、连接、发送、接收;各次 socket 操作还有连接/停滞时限。不会重连或自动重试传包,所有退出路径释放句柄。
收到完整 `2170` JSON 且整数 code=0、客户端实际发送 ROM 字节数等于文件大小,才返回 `PROTOCOL_SUCCESS_POSTCHECK_REQUIRED`。acknowledged=true 和 desc 只记录设备应答,不能证明烧录或启动完成。之后有界等待并重新查询同一 SN 的指定版本字段;发送/接收超时、断开或错误也应先只读检查状态,不能自动重刷。缺失验收字段不阻断已授权传包,但必须在最终验收中保留 `INCOMPLETE`。
## 验证范围
2026-10-19,全部118项离线测试通过,其中 V1 查询/发现24项、升级14项、适配器28项。V1 测试运行实际编解码及发送器,覆盖已知 MD5报文、分片发送/响应、计数、错误应答、文件变化、总/停滞时限、精确身份、摘要门槛、默认不写入及无自动重刷。
同日,在一台用户授权 V1 设备上完成一次19,420,244字节 ROM 下发,收到同命令code=0/desc=update success。随后连续两次只读查询与原 SN/dev_type 一致,原生 firmware 从2.0.1变为2.0.2、dev_ver 从2.0.20260908.5变为2.0.20260908.6。指定 outer.version 仍缺失,验收为 INCOMPLETE;不改用原生字段冒充指定字段通过。该实测不代表所有 V1 固件兼容,现场身份及日志独立保存。