fix(SerialMate): v0.1.2 解析模式不再吞数据——不成帧字节透传显示

背景: 用户接非 DLPilot 协议设备(COM25)开解析模式接收区一片空白——_dispatch_rx 在解析模式只上抛完整合法帧, 不成帧字节(纯文本日志/别的协议/波特率不符乱码)被 FrameParser 重同步时静默丢弃。用户明确定位: 首先是基础串口调试工具, 自定义协议解析是附加项, 附加能力不得影响本体功能。

修复: protocol.py FrameParser 丢弃字节累积进 garbage(新增 drain_garbage(), feed() 返回值不变); link.py 新增 on_garbage(data, ts) 回调, 每批无条件 drain(未接回调也不累积); main.py 把 on_garbage 并入 raw 事件与透传行同格式显示, 解析协议帧开关补 tooltip, 版本 0.1.2。半帧前缀扣留语义有意保留(可能补全成真帧, 至多扣一个前缀长度)。

自检: selftest 8b +10 项(纯文本全透出/噪声+帧+尾字节/坏CRC帧字节全透出/半帧头扣留补全), loop 3b +3 项, gui 5b +2 项; 全量 67+21+68 项 PASS; exe 已重建。README/AGENTS.md(不变量 5a) 同步。
This commit is contained in:
2026-10-16 19:08:55 +08:00
parent ac76c10132
commit 8e91e661f1
8 changed files with 118 additions and 11 deletions
+38 -3
View File
@@ -93,6 +93,14 @@ SerialMate/
5. **解析重同步策略**:前缀令牌逐位对齐(HDR/字面量须匹配、ID 通配),LEN 值经
口径换算为 payload 长度,负值视为伪帧头逐出;CRC 失配丢 1 字节重同步——
通用工具不预设合法 LEN 区间(与 DLPilot 的 LEN 范围预判不同)。
5a. **解析不吞数据(v0.1.2 起的产品语义)**:串口助手是本体、协议解析是附加层。
FrameParser 重同步丢弃的字节累积进 `garbage`,`link.SerialLink._dispatch_rx`
每批 `drain_garbage()` 无条件取走(未接回调也不许在解析器里无限累积),
经 `on_garbage(data, ts)` 上抛;GUI 把它并入 `('raw', ...)` 事件,与透传行
同格式显示。纯文本设备/波特率不符的乱码在解析模式下必须全可见。
例外:只匹配上前缀、还在等后续字节的"半帧"缓冲不算垃圾(可能补全成真帧),
字节流恰好在帧头后截断时会扣留至多一个前缀长度的字节——可接受,勿改成
超时强制吐出(会把慢速真帧撕碎)。改此语义需同步 selftest 8b / loop 3b。
6. **ID 位不校验只透出**:`Frame.code` 原样上抛(布局无 ID 时为 None,GUI 日志
与 selftest 均需兼容 None),TYPE_NAMES 仅用于显示译码(DLPilot 语义)。
7. **BASE_DIR 语义**(config.py):frozen 时 =exe 所在目录,源码运行时 =src/;
@@ -150,9 +158,9 @@ SerialMate/
```powershell
python -m compileall -q . # 全模块可编译
python selftest.py # 协议回归(47 项, 改 protocol.py 后必跑)
python selftest_loop.py # 链路回环(需 pyserial, 改 link.py 后必跑)
python selftest_gui.py # GUI 功能回归(offscreen, 改 main.py 后建议重跑)
python selftest.py # 协议回归(67 项, 改 protocol.py 后必跑)
python selftest_loop.py # 链路回环(21 项, 需 pyserial, 改 link.py 后必跑)
python selftest_gui.py # GUI 功能回归(68 项, offscreen, 改 main.py 后建议重跑)
python main.py --seconds 5 # GUI 冒烟(源码); offscreen: set QT_QPA_PLATFORM=offscreen
python build_exe.py # → ../release/SerialMate.exe(缺 PyInstaller 自动装)
python package_release.py <版本> # → ../release/SerialMate-v<版本>-win64.zip
@@ -196,6 +204,33 @@ tag/release 命名 `SerialMate-vX.Y.Z`,zip 命名
## 7. 进度记录
### v0.1.2(2026-10-16,接收语义修复:解析模式不再吞数据)
背景:用户接 COM25(非 DLPilot 协议设备)开解析模式,接收区一片空白——
`_dispatch_rx` 在解析模式只上抛完整合法帧,不成帧的字节被 FrameParser 静默
丢弃;用户明确产品定位:**首先是基础串口调试工具,自定义协议解析是附加项**,
附加能力不得影响本体功能。
已完成:
- protocol.py:FrameParser 丢弃字节不再销毁——重同步逐出的字节累积进
`garbage`,新增 `drain_garbage()` 取走清空;`clear()` 一并清垃圾;
`feed()` 返回值不变(旧用法零改动)。
- link.py:新增 `on_garbage(data, ts)` 回调(区别于透传模式的 `on_raw`,
语义可分但 GUI 同样并入 raw 事件显示);`_dispatch_rx` 每批 drain 无条件
执行(未接回调也不累积),有字节且接了回调才上抛,ts=同一批到达时刻。
- main.py:接线 `on_garbage → ('raw', ...)`;"解析协议帧(收)"补 tooltip
说明两模式语义;APP_VERSION 0.1.2。
- 例外语义(有意为之):只匹配前缀、等待后续字节的半帧缓冲不算垃圾
(可能补全成真帧);字节流恰在帧头后截断时扣留至多一个前缀长度。
- 自检扩充:selftest 8b(纯文本全透出/噪声+帧+尾字节/坏CRC帧字节全透出/
半帧头扣留后补全成帧)+10 项;selftest_loop 3b(解析模式非帧字节经
on_garbage 透出、回环 TX 帧只算非帧字节)+3 项;selftest_gui 5b
(on_garbage 接线+非帧字节日志行)+2 项;全部通过。
- README 协议解析段同步"解析不吞数据"语义;exe 重建(v0.1.2);
zip/Release 未发布(待用户验收)。
待办 / 计划:无新增,沿用 v0.1.0 待办。
### v0.1.1(2026-10-10,接收路径修复:时间戳失真 + 显示延迟累积)
背景:FilmForge 固件联调(GD32F405 RS485 115200,M2 连续温度上报 2~10 帧/s)