259 lines
22 KiB
Markdown
259 lines
22 KiB
Markdown
# AGENTS.md — DLPilot 工程档案(开发约束与进度)
|
||
|
||
> 人类文档 [README.md](README.md) 回答"这是什么、怎么用";本文记录"代码怎么组织、
|
||
> 怎么构建发布、改动时哪些约束不能破坏",兼作本工具的进度记录。
|
||
> 修改本目录代码前先读完本文。仓库整体的开发需求与进度管理见根目录 `agent.md`。
|
||
|
||
## 1. 项目定位
|
||
|
||
仓库 `HW-Debug-Tools` 是 LT8619C(HDMI→RGB888)→ DLPC3421 投影转接板的**调试上位机工具集**,
|
||
上游主仓库(固件)为 `hulk/LT8619C_DLPC3421_HDMI`(同 Gitea 实例 `gitea.hulk.wang`),
|
||
上游固件本机路径 `E:\Hulk-Coding\LT8619C_DLPC3421_HDMI`;工具仓库路径 `E:\Hulk-Coding\HW-Debug-Tools`。
|
||
DLPilot 工作在两端:HDMI **源端**(PC 显卡侧,EDID/分辨率/图案)与**光机控制端**
|
||
(RS485 → 板载 GD32E230 网关 → DLPC3421)。寄存器语义判读基线(0x606E 位交换 /
|
||
0x606D 整组顺序)与光机协议规程都在上游仓库 `doc/architecture/` 与 `protocols.md`,不在本仓库。
|
||
|
||
## 2. 目录契约(重要)
|
||
|
||
```
|
||
DLPilot/
|
||
├── src/ 源代码区 —— 只有这里可以手改(logos/ 改图标源后重跑 make_ico.py)
|
||
├── assets/ 生成资产区 —— gen_*.py 的产物(PNG 图案),可随时再生成,改动需提交
|
||
├── release/ 产物区 —— 机器生成,禁止手改:DLPilot.exe、pattern_slots.json、
|
||
│ bw/solid 图案(package_release.py 从 assets/ 平铺复制来,均入库)、
|
||
│ *.zip(gitignore,只上传 Release)。release/ 本身=完整可直接运行的
|
||
│ 发布文件夹(exe+附属平铺),内容与 zip 一致
|
||
├── README.md 人类文档
|
||
└── AGENTS.md 本文
|
||
```
|
||
|
||
划分原则:**"人写的"在 src/,"生成的"按去向分 assets/(随包分发)与 release/(直接交付)**。
|
||
新文件必须落对区域;不要在 src/ 外新建源码,不要手改 assets/ 下的 PNG(改生成脚本再跑)。
|
||
|
||
### 文件角色速查
|
||
|
||
| 文件 | 角色 |
|
||
|---|---|
|
||
| `src/hdmi_gui.py` | 入口: argparse 命令行分发(--dump/--edid-fields/--test-pattern/--dlpc-cmd/--seconds), GUI 委托 app_fluent |
|
||
| `src/app_fluent.py` | PySide6-Fluent-Widgets 主界面: 双栏仪表盘(左 HDMI 源端五卡/右 光机五卡), 光强/定时快捷滑条 |
|
||
| `src/display_win.py` | Win32 显示器枚举/分辨率切换/智能拓扑(纯 ctypes) |
|
||
| `src/edid_parse.py` | EDID 1.4/CEA-861 解析(纯标准库, 上游 lt8619c_edid.c 以此为参考解码器) |
|
||
| `src/patterns.py` | 测试图案全屏投屏窗口(tkinter, ESC 退出, 测试卡区域 1:1 居中) |
|
||
| `src/config.py` | 运行目录定位(BASE_DIR)与 pattern_slots.json 读写(slots/area/serial 三键) |
|
||
| `src/dlpc_rs485.py` | 光机 RS485 协议模块: 帧构造/增量解析/译码表/预设命令/串口线程(DLPC485) |
|
||
| `src/selftest_rs485.py` | 光机协议自检(对照上游实测帧向量, 无硬件回归, 改协议代码后必跑) |
|
||
| `src/selftest_theme.py` | 主题切换回归(离屏, swatch 底色/渲染像素/标题字号, 改样式后必跑) |
|
||
| `src/selftest_log.py` | 收发日志上限与队列消费回归(离屏, 改 _dlpc_log/_poll_dlpc 后必跑) |
|
||
| `src/build_exe.py` | PyInstaller 打包 → `release/DLPilot.exe`(onefile/noconsole, 内嵌图标+pyserial+PySide6-Fluent-Widgets) |
|
||
| `src/package_release.py` | 复制图案到 release/(平铺) → `release/DLPilot-v<ver>-win64.zip`(校验栏位引用完整性; release/ 与 zip 内容一致) |
|
||
| `src/publish_gitea.py` | 建/复用 Gitea Release 并上传 zip(tag 默认取 zip 文件名) |
|
||
| `src/hdmi_source.ps1/.bat` | 独立 PowerShell 命令行工具(自包含,与 GUI 无代码共享) |
|
||
| `src/gen_bw_patterns.py` | 生成 `assets/bw_*.png` ×5(640x360 黑白,需 Pillow) |
|
||
| `src/gen_solid_colors.py` | 生成 `assets/solid_*.png` ×10(800x600 纯色,需 Pillow) |
|
||
| `src/la_wave_analyzer*.py` | 逻辑分析仪 CSV 波形判读(2/3 通道,40MHz 像素时钟假设) |
|
||
| `src/logos/make_ico.py` | svg/png → ico(写在其自身目录) |
|
||
| `release/pattern_slots.json` | 预置栏位:西门子星/波带片/综合测试卡,area=640x360;`serial` 键记忆光机串口 |
|
||
| `UI参考布局.svg/.png` | 界面布局设计稿(app_fluent.py 双栏布局的规格来源, 随分支入库) |
|
||
|
||
## 3. 代码不变量(改 hdmi_gui.py 必须维持)
|
||
|
||
1. **依赖分层**:CLI/显示/EDID/协议/配置模块(display_win/edid_parse/config/
|
||
dlpc_rs485)纯标准库;PySide6-Fluent-Widgets 是 GUI(app_fluent)的**硬依赖**(装了
|
||
才能开界面,CLI 不受影响),GUI 图案窗口使用 Qt,CLI 图案窗口由 patterns.py 使用 tkinter 创建。可选依赖
|
||
仍走"try-import + HAS_* 标志 + 缺失降级"模式:Pillow、pyserial——缺失时对应功能
|
||
禁用/提示安装,其余功能必须照常工作。
|
||
2. **模块边界**:hdmi_gui.py 只是入口, 不放实现; GUI 的显示器/EDID 访问走 display_win/edid_parse;ctypes 仅用于
|
||
单实例锁、Windows 标题栏与 frozen DLL 加载; pyserial 只准在 dlpc_rs485.py 里 import
|
||
(hdmi_gui/app_fluent 经 `dlpc_rs485.HAS_SERIAL` 与 `DLPC485` 类间接使用)。
|
||
3. **BASE_DIR 语义**(定义在 config.py):frozen(PyInstaller onefile)时
|
||
`BASE_DIR=exe 所在目录`(`sys.executable`),源码运行时 `=config.py 所在目录`
|
||
(即 src/)。所有用户数据(pattern_slots.json、自定义图片)都写/读自 BASE_DIR
|
||
**平铺**存放,不建子目录。
|
||
4. **自定义栏位 `file` 字段是裸文件名**:加载时 `os.path.join(BASE_DIR, file)` 解析,
|
||
因此 pattern_slots.json 引用的图片必须与 exe 同目录 —— package_release.py 正是按此平铺打包。
|
||
5. **exe 自包含**:图标经 `--add-data` 内嵌(运行时从 `_MEIPASS` 读);内置五种图案
|
||
(红/绿/蓝/棋盘格/网格线)由程序绘制,运行时**不依赖** assets/;solid/bw PNG 只服务自定义栏位。
|
||
6. **DPI 感知**:进程启动即 `SetProcessDpiAwareness(2)`,图案窗口按物理像素定位,勿移除。
|
||
7. **智能显示拓扑(勿改回无条件扩展)**:启动时枚举"接入但不在桌面"的显示器,仅当其
|
||
EDID 厂商字节为转接板签名 `61 93`(压缩码 "XLS",上游 lt8619c_edid.c)时才
|
||
`SetDisplayConfig(SDC_TOPOLOGY_EXTEND|SDC_APPLY)` 拉回桌面,静默容错。动机:板卡
|
||
热插拔后 Windows 可能停留在"仅电脑屏幕"导致枚举不到板卡。用户主动选择的拓扑
|
||
(家里的"仅第二屏幕"等,未激活的是笔记本内屏,厂商非 XLS)一律不动。
|
||
8. **分辨率切换是临时的**:走 `CHANGEDISPLAYSETTINGS`(不写注册表),"恢复"用会话开始时快照。
|
||
9. **EDID 来源是注册表**(`HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\...\Device Parameters\EDID`),
|
||
不是 WMI/DDC;exe 的 noconsole 版无 stdout,`--dump/--edid-fields` 只在源码/控制台版可用。
|
||
10. **光机串口线程回调不直接碰 GUI**:DLPC485 的 on_event/on_status 在后台线程触发,
|
||
必须经 `queue.Queue` + Qt 定时器轮询投递回主线程(现行 `_poll_dlpc` 模式,
|
||
与 I2C-Inject 的 Injector 同源);退出路径(关窗与 `--seconds` 自动关)都会走到
|
||
`App.closeEvent()`,在那里 `dlpc.close()` 收线程。
|
||
11. **pattern_slots.json 格式**:`{'area', 'slots', 'serial'}` 三键共存;load 兼容旧版
|
||
纯数组(无 area)与无 serial 键两种历史格式,save 永远写全三键。`serial` 子键为
|
||
`{port, baud, bytesize(8/7/6/5), parity(N/E/O), stopbits(1/2)}`,旧配置缺子键按
|
||
默认 8-N-1 补齐。
|
||
12. **GUI = app_fluent.py 双栏仪表盘**(规格:`DLPilot/UI参考布局.svg`):左列 HDMI 源端
|
||
五卡(显示器/模式/EDID 信息/测试图案/hex),右列光机五卡(串口/数据/电源/命令/滑条),
|
||
支持的模式和 EDID 信息默认折叠;顶栏 Dark/Light/System 切换。Light/Dark 同时更新
|
||
Fluent 主题、Qt 调色板、容器样式与 Windows DWM 标题栏,勿只调用 setTheme。
|
||
**fluent 控件的自定义样式禁止直接 setStyleSheet**:setTheme 会用库自带 qss 重刷全部
|
||
已注册控件,直写样式随之丢失(v0.4.0 swatch 丢底色的根因)。须走
|
||
`setCustomStyleSheet(控件, lightQss, darkQss)`(qss 需覆盖 hover/pressed/disabled 态,
|
||
否则悬停瞬间被自带态样式盖回);仅 PushButton 等无 themeChanged 钩子的控件可幸存。
|
||
FluentLabelBase 系(StrongBodyLabel 等)例外:其 setTextColor 在每次切主题时整体重写
|
||
自定义槽,任何 setCustomStyleSheet 都会被冲掉——字号等改用 QFont(自带 label.qss 无
|
||
font-size 规则,QFont 不会被冲)。RGB swatch 底色回归测试见 selftest_theme.py。
|
||
PD 协议成功显示绿色,FPDO 仍独立判定。打包必须收集 `qfluentwidgets` 资源,并加入 Windows 系统 `icuuc.dll`,否则 QtCore 可能被其它 ICU DLL 解析失败。
|
||
|
||
## 4. 领域语义(测试值都有含义,勿"顺手改")
|
||
|
||
- 纯色值 55/AA/FF:55(01010101) 与 AA(10101010) 互为字节镜像对(检出位序颠倒/位交换),
|
||
FF(11111111) 全高基准;R/G/B 三行对应 RGB888 三字节组(R=D[23:16]/G=D[15:8]/B=D[7:0])。
|
||
- 800x600@60:LT8619C **demo 板** shadow EDID 首选时序(solid 系列分辨率与之一致)。
|
||
- 640x360:测试卡区域默认值(16:9 半分辨率,点对点检查用);full=铺满所选屏。
|
||
**同时是转接板光机 DLPC3421 的 nHD 面板原生分辨率**(该板 shadow EDID 只声明 640x360@60),
|
||
投 640x360 图案 + RS485 开光机 = 整链路 1:1 验证。
|
||
- bw 系列图案各自目的见 `src/gen_bw_patterns.py` 顶部清单注释。
|
||
- 光机 RS485 命令集(M730/M731/M732/M201/M202/M737/M999/M888/M7/M8/M1/**M303/M304**)语义、
|
||
帧格式 `D5 01 LEN <ASCII> CRC`(累加和校验)、错误码与**就绪门禁**
|
||
(DLPC 未就绪时 M730/M731/M732 被拒回 0xFF)以上游 `protocols.md` 为唯一权威,
|
||
本仓不维护协议文档副本;注意 **M7S0 是"开启"TEC 自动控温**(方向反直觉)、
|
||
M737 在定时投光中延迟应答(CLI 等待上限 35s)。
|
||
- **M303/M304/M305 载荷是二进制例外**(SQ52205 电源实测):成功载荷为大端原始值,
|
||
**不是 ASCII**——Frame.payload 解出来是乱码,必须走 `payload_bytes()` 取原始字节;
|
||
M303=u16 mV(12V 轨窗口 11400~12600),M304=s16 补码 mA(正=正向,固件原样上总线,
|
||
上位机按有符号解析,FF 06=−250),**M305=u32 mW(LEN=4,勿复用双字节解析;
|
||
恒非负,量程 0~295000,能量方向看 M304 符号;显示 mW→W 两位小数)**。
|
||
封装在 `payload_u16_be/payload_s16_be/payload_u32_be/format_power`,
|
||
回归向量在 selftest_rs485.py(M303/M304 真机帧,M305 算法推演帧)。
|
||
- **电源自检序列**(M301 协议→M302 挡位最大电流→M303 实测母线电压,帧驱动状态机
|
||
`_pd_on_frame/_pd_seq`,超时 3s/步):FPDO 判定 = 电压就近挡(标准 PD 固定挡
|
||
5/9/12/15/20/28V,±5% 容差)+ M302 挡位电流;**12V 且 ≥3A 绿底,挡位不符红底,
|
||
无匹配挡 ERR**。应答按 TYPE=0xF0 判成功;
|
||
CH224Q 电压配置寄存器(0x0A)只写不可读,挡位只能实测判定。
|
||
- **功率检测** = M303+M304+M305 序列 → 读数框 电压V / 电流mA / 功率W(M305 u32 mW
|
||
换算两位小数);各步载荷长度按 kind 校验(2/2/4 字节),坏帧中止显示 ERR。
|
||
|
||
## 5. 构建 / 发布流水线(全部在 src/ 下执行)
|
||
|
||
```powershell
|
||
python gen_bw_patterns.py ; python gen_solid_colors.py # 仅当改了图案生成逻辑
|
||
python build_exe.py # → ../release/DLPilot.exe(缺 PyInstaller 会自动 pip install)
|
||
python build_exe.py --debug # 附加带控制台的 DLPilot-console.exe(调试 --dump 用)
|
||
python package_release.py <版本> # → ../release/DLPilot-v<版本>-win64.zip
|
||
python publish_gitea.py ../release/DLPilot-v<版本>-win64.zip --replace --insecure # 上传(需 GITEA_TOKEN)
|
||
```
|
||
|
||
发布约定:
|
||
- tag/release 命名 `DLPilot-vX.Y.Z`,zip 命名 `DLPilot-vX.Y.Z-win64.zip`(publish_gitea.py
|
||
依赖此命名从文件名推 tag);
|
||
- **pattern_slots.json 与 release/ 下平铺的图案 png 改动跟随源码/资产生成提交入库;
|
||
exe 不入库**(2026-10-13 起全仓 `.gitignore` 挡 `*.exe`,交付物只走 Gitea
|
||
Release 附件,本地保留);**zip 永不入库**(.gitignore 已挡);
|
||
- publish_gitea.py 幂等:release 已存在则复用,同名资产默认跳过,`--replace` 删旧重传;
|
||
- token 读环境变量 `GITEA_TOKEN`:本机已用 setx 持久化为用户级变量(新开的会话/终端自动
|
||
继承,值不入库;在 setx 之前启动的进程读不到,需重开终端),急用时也可临时传 `--token`;
|
||
- Gitea 实例 `gitea.hulk.wang`,API 走 https(443),git 走 ssh(1234)——从 origin 远程自动解析;
|
||
python urllib 连该实例会在部分请求上报 `SSL: UNEXPECTED_EOF`,**实际发布需加 `--insecure`**;
|
||
- 本实例 Gitea 的 API 兼容性怪癖:`GET /releases/tags/{tag}` 返回的 `assets` 是纯数组,
|
||
而 `GET /releases/{id}` 是 `{items:[...]}` —— publish_gitea.py 已按两种形状兼容,勿"简化"回去。
|
||
|
||
## 6. 已知坑(历史踩过,勿重蹈)
|
||
|
||
- onefile 运行时 `__file__` 指向临时解压目录 `_MEIPASS`,定位 exe 必须用 `sys.executable`(§3.3);
|
||
- 重新打包前旧 exe 可能被残留进程占用 → build_exe.py 会 taskkill 同名进程,手改打包脚本时保留;
|
||
- 打包后本机图标缓存不刷新:`ie4uinit -show`,不是产物问题;
|
||
- 改图标流程:改 svg → `make_ico.py` 生成 ico → 重新打包(ico 同时是文件图标与运行时窗口图标);
|
||
- GUI 与 hdmi_source.ps1 各自独立实现显示器枚举,行为可能微差(GUI 与 `-List` 序号一致,
|
||
但与"设置"面板序号无保证);多屏操作前先确认序号;
|
||
- `pattern_slots.json` 兼容两种历史格式,写出只写新格式(详见 §3.11);
|
||
- `--seconds` 冒烟在已有 DLPilot 实例(含用户开着的 exe)运行时会"挂起":run_gui
|
||
检测到单实例互斥后弹模态框等点击。无头验证改用直启 `App(5)` 的等效脚本,或先关实例;
|
||
重打包同理——build_exe.py 会 taskkill 同名进程,等于替用户关掉开着的实例;
|
||
- 旧版 `app_gui.py` 仅保留作历史对照,当前入口使用 `app_fluent.py`;新增或修改界面时
|
||
应遵循 PySide6-Fluent-Widgets 的控件和 Qt 布局,不要把旧版 CustomTkinter 依赖带回入口。
|
||
|
||
## 7. 验证清单(改完代码后)
|
||
|
||
1. `python -m compileall -q src`(在 DLPilot/ 下) —— 全模块可编译;
|
||
2. `python selftest_rs485.py` —— 光机协议回归(改 dlpc_rs485.py 后必跑,向量来自上游 protocols.md);
|
||
3. `python selftest_theme.py` —— 主题切换回归(改 app_fluent.py 涉及样式/主题后必跑;
|
||
离屏渲染,Dark/Light 往返后校验 swatch 底色样式与渲染像素、标题字号);
|
||
3b. `python selftest_log.py` —— 收发日志上限/队列消费回归(改 `_dlpc_log`/`_poll_dlpc`
|
||
后必跑;600 行封顶 500、坏条目不中断 drain);
|
||
4. `python hdmi_gui.py --seconds 5` —— GUI 冒烟(自动开关);
|
||
5. `python hdmi_gui.py --test-pattern Checker --area 800x600 --seconds 3` —— 投图链路;
|
||
6. `python hdmi_gui.py --dump` —— EDID 解算不抛异常;
|
||
7. `python hdmi_gui.py --dlpc-cmd M999`(不带 --port)—— 应明确报错而非崩溃(无硬件时的优雅降级);
|
||
8. `python build_exe.py` → 双击 release/DLPilot.exe 确认图标/双栏布局/投图/光机区渲染;
|
||
9. `python package_release.py <版本>` —— 不报"引用图片缺失"即栏位完整性 OK。
|
||
|
||
## 8. v0.4.0 进度记录(2026-09-24)
|
||
|
||
- 入口已切换 `app_fluent.py`;历史 `app_gui.py` 保留,不改其历史版本号。
|
||
- 本次验证:源码编译通过、RS485 自测 ALL PASS、Qt 离屏浅色渲染、正式 EXE 定时退出码 0。
|
||
原生桌面自动化不可用,未完成成品 Light 截图;未将硬件功能标记为本次实机验证通过。
|
||
- 发布已将本次源码、文档、EXE 纳入同一个提交(`74b64dc`),远端标签 `DLPilot-v0.4.0`
|
||
指向该提交、附件已核对;zip 不入库。
|
||
- `release/pattern_slots.json` 的本机串口记忆改动属于运行态配置,勿随提交悄悄带入;
|
||
发布使用仓库预置配置,临时打包后恢复本机文件。
|
||
- 关联动态:EDID-Viewer 已于 2026-09-25 从本工具的"源端 EDID 查看"需求独立成工具
|
||
入库并发布 v0.1.0,与本目录无代码共享;I2C-Inject 已标记暂停开发(详见根 `agent.md`)。
|
||
|
||
## 9. v0.4.0 后修复记录
|
||
|
||
- 2026-09-28 修复"切换 Light 后 R/G/B hex 按钮底色丢失、切回 Dark 也不恢复":根因是
|
||
fluent 控件直接 `setStyleSheet` 的自定义样式在 `setTheme` 时被库重刷的自带 qss 整体
|
||
覆盖(任何方向的切换都会丢,非 Light 特有)。swatch 改走 `setCustomStyleSheet`(qss
|
||
覆盖 hover/pressed/disabled 态),同病的顶栏标题 24px 字号改用 QFont(FluentLabelBase
|
||
的自定义槽被库的 setTextColor 每次切主题重写,见 §3.12)。新增 `src/selftest_theme.py`
|
||
离屏回归(样式表存活 + 渲染像素比对),本次验证:compileall / selftest_rs485 /
|
||
selftest_theme / GUI 冒烟全部通过。
|
||
- 2026-09-28 以 v0.4.1 重新打包:APP_VERSION → 0.4.1,`build_exe.py` 生成新
|
||
release/DLPilot.exe(67.1 MB,exe `--seconds 5` 定时退出冒烟 exit 0),按 §8 约定
|
||
临时还原预置 pattern_slots.json 后 `package_release.py 0.4.1` 生成
|
||
`DLPilot-v0.4.1-win64.zip`(66.8 MB,zip 内为预置 COM15 配置,本机 COM5 运行态
|
||
已还原未入库)。Gitea Release 已发布:tag `DLPilot-v0.4.1` 指向提交 `62b325c`
|
||
(源码+exe+文档同一提交),资产 `DLPilot-v0.4.1-win64.zip`(66.8 MB),
|
||
https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases/tag/DLPilot-v0.4.1 。
|
||
发布说明用 --notes-file 传入(内置 DEFAULT_NOTES 模板还是 v0.1.0 旧内容,下次
|
||
发布记得先写说明文件)。
|
||
- 2026-09-28 第二修:"串口未选/选错点连接后窗口被拉长、刷新按钮够不到"。根因:
|
||
pyserial 原始异常串(`could not open port '': FileNotFoundError...`)整段塞进
|
||
状态 BodyLabel,QLabel 不换行时最小宽度=整行文本宽,把右列参数行最小宽度撑爆。
|
||
三层修复:①`_dlpc_toggle` 空串口直接短提示返回(不再先写 SERIAL_CFG/save_slots
|
||
再 open——旧代码这顺序还会把本机串口记忆覆写成空串,本机 COM5 记忆即这样丢失过,
|
||
已手工修回);②dlpc_rs485 open 失败消息分类为短提示(被占用/不存在/其它),
|
||
完整异常改走 on_event 进收发日志;③`lbl_dlpc_st.setWordWrap(True)` 兜底。
|
||
验证:compileall / selftest_rs485 ALL PASS / 离屏断言(空串口提示、长文本下标签
|
||
最小宽度<300 可换行)/ GUI 冒烟 / 新 exe `--seconds 5` exit 0;v0.4.1 exe(15:05)
|
||
与 zip 均已用该修复重打。
|
||
- 2026-09-28 v0.4.2 两处 UI 小修:①"串口数据 · 收发日志"卡的"清空"按钮原本自占
|
||
一行(_card 的标题行是独立 row,按钮行加在其下),与标题错位且多占一行高度——
|
||
`_card()` 增加 `trailing` 参数把按钮并入标题行右端;②v0.4.0 fluent 重写把旧版
|
||
app_gui.py 光机命令卡首行的快捷按钮排(开光机/关光机/查版本/软件重启/开TEC/
|
||
关TEC/TEC33.0°C)整行丢失,开/关光机只能走预设下拉——本次按旧版排布原样恢复,
|
||
位于电流行与预设行之间(命令直发 `_dlpc_send`,无新增协议逻辑)。
|
||
验证:compileall / selftest_rs485 / selftest_theme ALL PASS;离屏渲染断言"清空"
|
||
与标题垂直中心差 0px、7 个快捷按钮齐全;真实桌面冒烟 exit 0。APP_VERSION → 0.4.2
|
||
并重打包。v0.4.2 已发布:tag `DLPilot-v0.4.2` 指向提交 `7bd9943`(源码+exe+文档
|
||
同一提交),资产 `DLPilot-v0.4.2-win64.zip`(66.8 MB,zip 内为预置 COM15 配置,
|
||
本机 COM5 运行态已还原未入库),
|
||
https://gitea.hulk.wang/hulk/HW-Debug-Tools/releases/tag/DLPilot-v0.4.2 。
|
||
本次发布说明已用 --notes-file 传入(临时文件,未入库)。
|
||
- 2026-10-13 v0.4.3 修复"长会话越跑越卡、命令点了没反应"(FilmForge 同案):
|
||
根因是 `_dlpc_log` 的手工 textCursor 裁剪用了**实例级枚举访问**
|
||
(`cursor.Start`/`cursor.BlockUnderCursor`),PySide6 6.11 移除该形式,收发日志
|
||
超 500 行后每次追加必抛 AttributeError;异常又逃出 `_poll_dlpc` 的 drain 循环
|
||
(旧 try 只捕获 queue.Empty),每 tick 最多消费到第一条 event,`_dlpc_log_q`
|
||
棘轮积压、日志裁剪/自动滚动全失效;电源自检/功率检测序列在 `_pd_step_next()`
|
||
之前的 `_dlpc_log` 调用处被打断,`_pd_seq` 永不清空,后续所有手动命令被
|
||
"序列进行中"拦截直到断开重连。整改:①改用 `setMaximumBlockCount(500)` 环形
|
||
裁剪(O(1),不依赖枚举写法);②`_poll_dlpc` 改逐事件兜底 try/except,单条异常
|
||
只打栈放弃该条、不再中断本轮消费;③新增 `selftest_log.py` 回归(600 行封顶 +
|
||
坏条目 drain 不中断)。验证:compileall / selftest_rs485 / selftest_theme /
|
||
selftest_log ALL PASS;GUI 冒烟 exit 0;`--dump` / `--dlpc-cmd`(无串口)正常。
|
||
APP_VERSION → 0.4.3 重打包(67.1 MB),按 §8 约定临时还原预置 pattern_slots.json
|
||
后 `package_release.py 0.4.3` 生成 `DLPilot-v0.4.3-win64.zip`(66.8 MB,zip 内
|
||
为预置 COM15 配置,本机 COM5 运行态已还原未入库)。遗留(未随本版处理):
|
||
`dlpc_rs485.py` 的 `except OSError` 把写超时(SerialTimeoutException)与设备
|
||
拔出混判,一次转换器停滞即断链误报"设备拔出"。
|