fix(packaging): 修复 Windows 安装与固件打包并完善客户端文案
- fix(installer): 修复低完整性产物无法写入临时目录的问题,并在 CI 打包前后检查完整性标签 - fix(firmware): 从本次 Cargo ELF 打包并同步配套镜像,修正短目录说明与 LLVM 搜索顺序 - fix(installer): 修复中文完成页和页眉遮挡,侧栏使用等比缩放的原始 Logo - style(client): 应用图标增加圆角,统一“裁判系统客户端”命名 - fix(config): 安装提示改用可选本地热点配置,排除 Wi-Fi 凭据 - docs: 润色项目说明并统一裁判系统术语 - test(packaging): 补充 Windows 完整性和固件打包回归,覆盖外部输出目录、旧镜像与重复生成 验证:Windows NSIS 构建及原生页面预览;通用与本地安装配置编译;固件 release 构建、重复打包和客户端离线校验;6 项固件打包回归与 Windows 权限回归;git diff --check。未执行实机烧录。
This commit is contained in:
+12
-24
@@ -8,7 +8,7 @@ protocol/ 线路格式 + 帧重组 (23 个单元测试,无 ESP-IDF 依
|
||||
desktop/ 桌面客户端 (RMIC::2026,Tauri v2 + React + Rust,两种身份)
|
||||
```
|
||||
|
||||
编码与帧重组出错时,板上通常只表现为没有画面,难以定位。因此这里提供不依赖板卡的主机测试。
|
||||
编码与帧重组出错时,板上通常只表现为没有画面,难以定位。因此这里提供不依赖裁判系统的主机测试。
|
||||
|
||||
在宿主架构上运行测试:
|
||||
|
||||
@@ -38,8 +38,7 @@ cd protocol && cargo test
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
两块板子不区分队伍——它们只知道自己是谁(MAC 派生的 id),"哪一边"由客户端决定。
|
||||
烧同一份固件即可,配置在客户端一侧。
|
||||
两块板子不区分队伍,只通过 MAC 派生的 id 标识自身,所属队伍由客户端配置决定。因此,两块板子可以烧录同一份固件。
|
||||
|
||||
## 线路格式
|
||||
|
||||
@@ -75,20 +74,18 @@ cd protocol && cargo test
|
||||
|
||||
### 四个设计决定
|
||||
|
||||
**27 字节不凑整。** 头只占每个 1427 字节数据报的 1.9%,而为对齐在固件和客户端两侧
|
||||
各写一段手写偏移常量,更容易引入静默错位。
|
||||
头长保留为 27 字节,不额外补齐。它只占每个 1427 字节数据报的 1.9%;为对齐而在固件和客户端分别维护手写偏移常量,反而更容易引入不易察觉的错位。
|
||||
|
||||
**`sender_id` 是多路的前提。** 裁判终端同时收两块板子,靠它在同一端口上区分来源。
|
||||
|
||||
**`width`/`height` 每个分片都重复携带**(不只是第 0 个),这样每个数据报都能独立
|
||||
解析,中途加入的接收端也能立刻知道分辨率。
|
||||
|
||||
**`version` 不匹配就拒收**,而不是按错误布局继续解析——后者会表现为随机崩溃或画面
|
||||
错乱,比拒绝连接难查得多。
|
||||
`version` 不匹配时直接拒收。继续按错误布局解析会导致随机崩溃或画面错乱,比拒绝连接更难排查。
|
||||
|
||||
## 通告里的版本信息
|
||||
|
||||
`Hello` / `Heartbeat` 的负载是**向后兼容的一截**,现在 10 字节:
|
||||
`Hello` / `Heartbeat` 的负载保留向后兼容的字段,目前共 10 字节:
|
||||
|
||||
```text
|
||||
相对 HEADER_LEN 的偏移
|
||||
@@ -102,15 +99,13 @@ cd protocol && cargo test
|
||||
|
||||
三个决定:
|
||||
|
||||
- **旧的 2 字节 `fw` 保留不动**。老客户端只读它,多余的字节不看,所以一次固件更新
|
||||
不会把还在用旧客户端的机器踢下线。
|
||||
- **新客户端接受只有 2 字节的老固件**:版本与构建号回到 0("未知"),协议号退回帧头里
|
||||
的那个。界面显示"版本未知",而不是一个看起来像真值的 `0.0.0`。
|
||||
- 保留旧的 2 字节 `fw` 字段。老客户端只读取该字段并忽略后续字节,因此更新固件不会使旧客户端因新增字段而断连。
|
||||
- 新客户端接受仅含 2 字节负载的老固件通告:版本与构建号设为 0(“未知”),协议号使用帧头中的值。界面显示“版本未知”,避免将 `0.0.0` 当作实际版本。
|
||||
- **通告用宽松的帧头解析,视频帧不用**。见下一条。
|
||||
|
||||
### 为什么通告允许协议不匹配
|
||||
|
||||
严格解析会丢弃 `version != PROTOCOL_VERSION` 的数据报,以避免按错误布局解析视频。若通告也被丢弃,客户端便无法发现协议不同的板卡,也无法解释没有画面的原因。
|
||||
严格解析会丢弃 `version != PROTOCOL_VERSION` 的数据报,以避免按错误布局解析视频。若通告也被丢弃,客户端便无法发现协议不同的裁判系统,也无法解释没有画面的原因。
|
||||
|
||||
`Hello::decode` 使用 `decode_header_lenient`,保留魔数、长度和字段校验,允许版本不匹配。读出 `proto` 后,客户端可以显示双方协议号,并提示重新烧录。
|
||||
|
||||
@@ -138,18 +133,14 @@ UDP 不保证数据报的顺序和到达。接收端等待下一张完整帧,
|
||||
|
||||
### 按发送方分开
|
||||
|
||||
**每个发送方必须有自己的重组器。** 两块板子的 `frame_id` 各自独立计数,塞进同一个
|
||||
重组器会让它们互相顶掉,两路都出不来。
|
||||
每个发送方必须使用独立的重组器。两块板子的 `frame_id` 分别计数,若共用重组器,两路数据会互相覆盖,导致两路都无法交付画面。
|
||||
|
||||
### 重复分片必须去重
|
||||
|
||||
`FrameAssembler` 按分片下标记录是否收到,重复的直接跳过且不计数,并显式确认最后一个
|
||||
分片确实到过。
|
||||
|
||||
用单一计数 `seen >= expected` 判断收齐不够健壮:一个丢失的分片若能被某个分片的副本
|
||||
凑数,计数就达标了,而缓冲区里留着空洞,交出去一张尾部是 0 的 JPEG。两个测试专门覆盖
|
||||
它(`a_duplicate_cannot_complete_a_frame_with_a_hole`、
|
||||
`a_gap_that_is_never_filled_never_yields_a_frame`)。
|
||||
仅用计数 `seen >= expected` 判断是否收齐并不可靠:重复分片可能补足计数,但丢失位置仍为空,最终交付的 JPEG 尾部会留下 0。两个测试覆盖这一情况(`a_duplicate_cannot_complete_a_frame_with_a_hole`、`a_gap_that_is_never_filled_never_yields_a_frame`)。
|
||||
|
||||
一次历史测试使用一到两个订阅者,20 秒收到 2000 多个分片;固定端口与临时端口两种方式均未观察到重复投递。去重用于保证重组正确性。重复片若被误计数,可能在帧率正常、没有报错时偶发地产生无法解码的 JPEG。
|
||||
|
||||
@@ -199,8 +190,7 @@ UDP 不保证数据报的顺序和到达。接收端等待下一张完整帧,
|
||||
|
||||
`id_from_mac()` 用固定长度输入的 FNV-1a 从 MAC 派生 `sender_id`。
|
||||
|
||||
**用 MAC 而不是 IP**,因为客户端要把绑定存进配置文件并在重启后继续有效——DHCP 换
|
||||
地址是常态,MAC 不会变。用 MAC 也意味着烧同一份固件即可,不需要任何"我是谁"的配置。
|
||||
使用 MAC 而非 IP,是为了让保存在配置文件中的绑定在重启后继续有效:DHCP 地址会变,MAC 不变。两块板子因此可以烧录同一份固件,无需另配设备身份。
|
||||
|
||||
返回值避开裁判终端保留值 0。测试检查结果稳定性与样例间是否碰撞,但不能证明哈希永不碰撞。
|
||||
|
||||
@@ -208,9 +198,7 @@ UDP 不保证数据报的顺序和到达。接收端等待下一张完整帧,
|
||||
|
||||
`scripts/udp_probe.py` 手写了这里的每一个常量,**不依赖本 crate**。
|
||||
|
||||
这正是它的价值:如果本 crate 的编码有错,脚本仍按文档解析,会立刻报出不一致。反面
|
||||
例子也有——它的 `role` 字节曾多填 12 个零字节,固件按偏移严格读取因而拒收,表现为
|
||||
"板子在线但 0 clients subscribed"。改协议时记得同步它。
|
||||
如果本 crate 编码有误,脚本仍按文档独立解析,可立即报出不一致。探测脚本本身也曾出错:`role` 字节曾多填 12 个零字节,固件按严格偏移读取后拒收,表现为“板子在线但 0 clients subscribed”。修改协议时需同步核对脚本。
|
||||
|
||||
## 装甲板
|
||||
|
||||
|
||||
Reference in New Issue
Block a user