Files
FilmForge/AGENTS.md
T
hulk 8035f9b7d3 GUI v0.2.9: fix chronic-lag root cause (log trim crash on PySide6 6.11) + 5 hardening fixes
- log trim used instance-level enum access (removed in PySide6 6.11), crashed
2026-10-12 16:14:53 +08:00

207 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FilmForge — AGENTS.md
## 项目约定
- **用途**:自制热压模具温控固件——塑型 PC 膜,负责加热驱动与测温(NTC),
对外走 RS485 数据口。基于 GD32F4xx 工程模板
(`https://gitea.hulk.wang/hulk/gd32f4xx_template_cmake_vscode`,源自
celalkismiroglu/gd32e23x-demo-suites-cmake 体系)。
- **命名**:仓库 `FilmForge`,固件工程 `FilmForge_FW`(产物自动命名
`FilmForge_FW_V<版本>_APP_<日期>.bin`),协议板卡类型码 `BOARD_TYPE_CODE 41`。
- **目标芯片**:GD32F405RET6(设备宏 `GD32F405`,IRC16M PLL 168MHz——板上无外部
晶振;硬件 FPU fpv4-sp-d16 / hard ABI;512K Flash,链接脚本 xE)。
- **串口角色与 PC 端映射**:
- debug 串口 = USART1(PA2 TX / PA3 RX,AF7,纯串口)→ PC 端 **COM4**;
printf 重定向到 USART1(`DEBUG_UART` 宏),`DEBUG_MODE` 打开后输出。
- 数据口 RS485 = USART0(PA9 TX / PA10 RX,AF7)+ DE 引脚 PA8(GPIO 手动切换
收发)→ PC 端 **COM5**(115200-8-N-1)。拉通阶段主循环回显。
- 注意 GD 外设编号比 STM32 小 1:PA9/PA10=USART0、PA2/PA3=USART1。
- **NTC 测温**:PC5(ADC0_IN15),硬件 10K 上拉、NTC 接 GND 侧。B 值公式换算,
`NTC_B_VALUE` 宏(3950/3435 未定,默认 3950,确认后修改);`R_PULL/NTC_R25`
均为宏,换料只改宏。
- **语言/工具链**:C(gnu11)+ ARM GCC(xpack 15.2.1 已验证)、CMake ≥ 3.20 +
Ninja、VSCode + CMake Tools + cortex-debug;工具链路径经 `GD32_GCC_BIN`。
- **目录约定**(沿用模板):
- `Build/` —— 构建树与产物(gitignore);
- `SDK/` —— CMSIS、标准外设库 V3.3.3、SEGGER_RTT、USB 库(`GD32_ENABLE_USB`
开关,默认 OFF,当前未用);
- `LD/` —— 链接脚本(默认 xE 512K);
- `Inc/`+`Src/` —— 应用层,板级引脚/开关集中在 `Inc/board_config.h`;
- `OpenOCD/` —— 工程内会话配置(GD-LINK/CMSIS-DAP + stm32f4x);
- `doc/` —— 芯片文档(数据手册/用户手册/固件库指南/AN,已齐备);
- `GUI/` —— 温控上位机(PySide6-Fluent,详见其 `README.md`,运行态
`filmforge_gui.json`/`logs/`/`build/`/`release/` 由 `GUI/.gitignore` 挡)。
- **编译方法**:
```bash
cmake --preset Debug && cmake --build Build/Debug
cmake --preset Release && cmake --build Build/Release
```
- **Git/网络经验**:origin = HTTPS(`https://gitea.hulk.wang/hulk/FilmForge.git`),
该实例 HTTPS/SSH 直传大包均不稳,已在本仓库配置
`http.proxy http://127.0.0.1:6789` + `http.sslVerify=false`(仓库级),
代理端口变化时用 `git config http.proxy http://127.0.0.1:<新端口>` 更新。
- **printf 浮点**:`--specs=nano.specs` 默认裁剪 `%f`(输出空白),已在
`cmake/project.cmake` 启用 `-u _printf_float`(F405 flash 充裕,ROM +8~10KB 无感)。
- **在线排查寄存器地址速查**(GD32F4xx):ADC0=0x40012000(RDATA@0x4C)、
USART0=0x40011000、USART1=0x40004400、GPIOA=0x40020000(OCTL@0x14)、
RCU:CTL0=0x40023800 / **PLL=0x40023804** / **CFG0=0x40023808**。
## 开发进度
### 已完成
- 模板就位(GD32F405RET6 / IRC16M 168MHz / 硬件 FPU / 上板验证过的模板体系)。
- **debug 串口**:USART1 PA2/PA3 @115200,printf 重定向 + RBNE 中断收环形缓冲
(模板已有,COM4 观测)。
- **RS485 数据口驱动**(`rs485.h/rs485.c`):USART0 PA9/PA10 AF7 + DE PA8 GPIO
手动切换;独立接收环形缓冲(预留一格策略 + PRIMASK 临界区);阻塞发送
(DE→TBE→TC→DE,防尾字节截断);`rs485_rx_clear()` 清接收缓冲。
- **NTC 测温驱动**(`ntc.h/ntc.c`):PC5 模拟输入 + ADC0 常规通道(软件触发单次
转换 + 校准),16 次采样均值 + 分压反解阻值 + B 值公式换算摄氏度
(含开路/短路电源轨检测)。
- `debug_uart_write()` 助手(uart.c):debug 口阻塞单字节发送。
- **命令协议框架移植**(`command.h/command.c`,自 E23x 移植):D5 帧协议
(D5 BOARD_TYPE LEN [cmd] CRC 累加和校验)+ B5 响应;数据源改为 RS485 收缓冲
(`rs485_rx_*`),响应经 `rs485_send` 发出(DE 自动切换);帧状态机 + CRC +
参数解析工具(uint_to_str/parse_uint_dec/parse_timer_parameter/find_parameter_value)
全套保留;通用命令骨架:**M888 软复位 / M999 版本号 / M9999 进 OTA**;
业务命令(加热/控温)待定义,switch 中扩展(TODO 注释有格式示例)。
- **命令协议 v1.0 定稿**(权威定义见根目录 `protocols.md`,帧 hex 全部脚本生成):
- M1 查温度 / M2 查上报状态 / M2S<ms> 上报间隔+开关(M2S0 停)/ M3 加热开关
(M3S1/M3S0/M3 查询)/ M4 目标温度(M4S<temp>/M4 查询)/ M888 / M999 / M9999
- **加热驱动 + PID 闭环实装**(`heat.h/heat.c`,PB12=HEAT_EN):
- 执行器:慢 PWM(载波 1s、占空 10% 步进 → 脉宽恒 >=100ms、开关频率恒 1Hz,
满足 2N7002K→VBE2412 PMOS 驱动电路 <=10Hz 约束)
- PID:500ms 周期(NTC 采样 100ms),位置式 + 积分限幅 + 输出量化 10% 档;
参数 Kp=8/Ki=0.05/Kd=0(初值,宏在 board_config.h,待整定)
- 安全:上电默认关;NTC 故障(OPEN/SHRT)强制关断;过温 150℃ 滞回保护;
未使能关断;使能切换/故障时复位 PID 积分
- 实测 30℃ 闭环(NTC 贴 PTC 鳍片):30s 爬升、超调 1.4℃(7%)、60s 收敛中
- M3/M4 已从软件桩切到 heat 模块(协议帧不变)
- 协议要点:全幂等(ack 丢可重发)、响应超时建议 300ms×3 次、温度一律 ASCII
- **PID 抗积分饱和**(5b24b95):条件积分(back-calculation lite)抑制输出限幅
期间的积分累积。
- **50℃→40℃ 阶跃验证脚本**(`temp_test_com.py`,工作区修改未提交):M2S500
全曲线采样,输出超调/settle 时间/稳态误差/降温段统计(结果以实跑为准)。
- **电源保持 PA11 实装**(`pwr_hold.h/pwr_hold.c`):上电最先拉高 PA11 维持
PMOS 自锁供电(先于一切外设初始化);`pwr_hold_off()` 预留软关机(置低即失电)。
- **专用 GUI 上位机 v0.1.0 完成**(`GUI/`,参照 DLPilot 分层:协议模块纯标准库 +
PySide6-Fluent 界面 + 自检 + PyInstaller):
- 文件角色:`filmforge_rs485.py`(帧/解析/串口线程 FF485)、`app_fluent.py`
(双栏仪表盘 + **自绘温度曲线**,未引第三方图表库)、`config.py`(设置记忆
filmforge_gui.json)、`filmforge_gui.py`(入口+CLI `--port/--cmd/--seconds-report`)、
`selftest_rs485.py`/`selftest_gui.py`(协议向量 / 离屏渲染+派发回归)、
`build_exe.py` → `release/FilmForge.exe`+发布 zip、`publish_gitea.py`
(tag `FilmForge-GUI-vX.Y.Z`)
- 功能:实测温度曲线+目标温度阶梯线同图(闭环监视)、M2 上报帧直采 / 上报关闭时
上位机自动轮询 M1 补点、NTC OPEN/SHRT 断口+故障标记、时间窗/暂停/窗口统计、
目标(M4S 0~200)/加热(M3S1 确认)/上报(M2S 100~60000)控制、连接自动同步
版本/上报/加热/目标、M888/M9999 二次确认+复位后重查、收发日志、CSV 记录
- **COM5 真机全链路验证通过**:M999=v41.0.0.1、M1/M2/M3/M4 查询、M2S500 上报
3s 收 6 帧、M2S0 停止;GUI 端到端(串口线程→队列→派发→曲线/状态芯片)实测通过
- 关键教训(勿重蹈,详见 `GUI/README.md`):①应答派发必须是 **FIFO 队列**(半双工
应答按发送序返回;单 pending 槽在连接序列 150ms 连发下被乱序击穿,实测 M2 的
OFF 被 M3 槽吃掉、M4 目标值混入曲线);②时间戳在串口线程读取点打(SerialMate
教训);③M4 目标应答路由窗口取条目生命周期 1.2s(适配器换向延迟实测可 >0.5s,
上报开启时才收紧 0.5s);④Fluent 控件样式走 setCustomStyleSheet(DLPilot 同款坑)
- 发布策略:GUI 产物(release/)暂不入库,本地 `python build_exe.py` 生成;发布走
`publish_gitea.py` 上传 zip(tag `FilmForge-GUI-vX.Y.Z`,与固件 tag 区分)
- **SerialMate 串口工具问题已定位**(见
`E:\Hulk-Coding\HW-Debug-Tools\SerialMate\ISSUE_rx_timestamp_and_lag.md`):
时间戳在 GUI 消费时打导致失真 + 接收日志无限增长致卡顿;待该工具修复后
再做长时间曲线联调。
- 工程改名:`FilmForge_FW`、`BOARD_TYPE_CODE 41`。
### 计划 / TODO(已提出尚未实现)
- [x] **RS485 拉通上板验证**:命令收发/响应/上报实测通过(固件端零丢字节,
响应 10ms 级实时);遗留为 USB-RS485 适配器方向切换丢包(换适配器解决)
与 SerialMate 显示层问题(见 ISSUE 文档)。
- [x] **NTC 测温上板验证**:NTC 支路修复后读数正常(23.6~25.9℃ 稳定)。
- [ ] **B 值确认**:温度计对照实测定 `NTC_B_VALUE`(3950/3435 二选一)。
- [ ] **适配器更换**:换可靠的 USB-RS485 适配器(当前自动方向切换间歇丢响应)。
- [x] **加热驱动 + PID 闭环**(PB12 慢 PWM 1s/10% 步进 + PID 500ms 周期,
安全保护齐全;实测 30℃ 闭环通过:30s 爬升、超调 1.4℃、60s 收敛中)。
- [ ] **PID 参数整定**:初值 Kp=8/Ki=0.05/Kd=0(board_config.h 宏),按真实
工况温度(80~120℃)与负载重新整定,抑制 ~7% 超调。
- [x] **专用 GUI 上位机 v0.2.0**:v0.1.0 已完成 COM5 真机全链路验证;v0.2.0 与
实装固件对齐——去除"固件预留/仅软件状态"旧表述(协议模块预设说明、温控
卡片标题/备注、开启加热确认弹窗改为真实控温警示、ack 提示),GUI README
与 publish_gitea 发布说明模板同步,protocols.md M3 表项去"预留";
监控逻辑简化:温度监控统一走 M2 周期上报(移除"M1 自动轮询"双通道及
poll 配置项,M1 仅手动单点查询),目标温度滑条范围 0~200→0~120(协议
上限 200 仍可手输)。**v0.2.1 真机回归修复**(COM5 实测暴露):①M4 查询
应答与周期上报帧同为 ASCII 浮点被误占(目标 chip 显示成实测值)→ 查目标
改应答驱动"暂停上报 M2S0→M4→自动恢复 M2S<ms>"链;②设定 ok 延迟 >1.2s
超时清队后状态 chip 与设备脱节(实测 M2S100 ok 迟到、chip 停 OFF)→ 8s
内晚到 ok 按发送时计划补偿应用;③断开按钮偶发不切换、断开后日志仍刷 →
连接按钮改意图驱动(点击即翻转、2s 未建立判丢失回退),已连接/已断开/
丢失全部入日志,连接同步序列每步发送前确认在线(修复序列整组被
"未连接串口"丢弃)。selftest 全过(新增 8 项回归用例);已打包冒烟并发布
Gitea Release `FilmForge-GUI-v0.2.1`(无应用图标——`logos/filmforge.ico`
仍缺位)。
- **GUI v0.2.2~v0.2.4(已修复待真机确认,未发布)**:
- v0.2.2:串口线程 `read(256)` 在持续帧流下攒满 256 字节才返回(win32 字节
间隔超时因帧间隔更短永不触发,100ms 上报 ≈2.5s 一批),曲线/命令/响应全部
3 秒一卡、一股脑一大坨——真机日志确认每簇 ≈25 帧、间隔恒 3s。已改
`read(in_waiting or 1)`,真机复测曲线实时、命令即发即回。
- v0.2.3:发送入口幂等去重——同命令未决时忽略重复发送(真机连点"停止"12 次
挤爆 8 条 pending 队列、"丢弃积压命令"刷屏),状态栏提示"应答中"。
- v0.2.4:目标阶梯线渲染 bug(v0.1.0 起潜伏)——`_target_points` 对最后一次
目标变更只画终点,从旧值斜拉直线到图表右缘(实测 57→41 被画成 2 分钟斜坡,
截图确认);改为纯阶梯(变更时刻垂直落变+水平延伸),数据本身无误。
- v0.2.5:排版调整——串口连接卡片从右列移到左列顶部,左列图表卡/右列日志卡
弹性拉伸填充,两列底边对齐。
- v0.2.6:对齐修复——双列改放同一滚动容器(整页统一滚动):原先两列各自包
QScrollArea 独立滚动,窗口化下底边错位(全屏正常);现两列高度锁定一致,
不足一屏各自拉伸到底、超出一屏整页滚动。
- v0.2.7:图标接入(logos/ 下 ico/png/svg 已就位)——exe 嵌入图标
(build_exe.py --icon,此前缺文件自动跳过)、窗口标题栏/任务栏/弹窗图标
(app+window 两级 setWindowIcon,_icon_path() 兼容源码态与 _MEIPASS 打包态)、
Windows 任务栏独立标识 AppUserModelID "hulk.FilmForgeGUI"。README"无应用
图标"遗留项关闭。
- v0.2.8:**慢性卡顿修复**——`_log()` 手工 cursor 裁剪(`cursor.Start`/
`BlockUnderCursor` 实例级枚举访问)在 PySide6 6.11 上必然抛 AttributeError,
日志超 500 行(100ms 上报 ≈50s)后每个 100ms tick 异常中止 `_tick` 后半段:
应答超时清理失效(pending 永不清 → "停止"点击被幂等去重永久拦截,实拍状态栏
"M2S0 应答中,已忽略重复发送")、RX 队列积压 ratchet(帧处理滞后 54ms→均值
1037ms/峰值 2701ms,日志/chip/曲线显示滞后数秒,"停止 5s 后才见命令发出"实为
日志显示积压,TX 本身 5~166ms 即出)、日志无限增长、CPU +30%。改原生
`setMaximumBlockCount(500)` 环形裁剪;selftest 新增"500 行封顶/封顶后可追加/
最新行在末尾"3 条回归。离屏 A/B 实测(GUI/_diag_latency_buggy.py,假固件
100ms 上报+定时点击):buggy 组 5.5 分钟异常 2241 次、修复组全程漂移 ≤15ms/
零异常/零积压。v0.2.7 exe(2026-10-10 打包)内嵌同版本 PySide6 6.11.2,
同带此 bug,需重新打包生效。
- v0.2.9:**整体审查修复 5 项**——①CSV 写失败(磁盘满/记录盘被拔)自动停记录
并提示,不再沿 _tick 帧处理路径抛 OSError 中止主循环(与 v0.2.8 日志裁剪同款
失效管道);②故障标记 faults 封顶 1000 条(曾是唯一无上限缓冲:NTC 抖动时
10 条/s 无限增长,且 _draw_faults 每 paint 全量扫描);③串口写超时单独捕获
SerialTimeoutException——只丢该条命令、链路保留,不再按 OSError 当"设备拔出"
关端口断链(适配器停滞曾迫使手动重连);④日志自动滚动仅在贴底时跟随(上报
运行时可上翻历史,不再被拽回底部);⑤冻结视图切片右缘同样二分(暂停时长不再
增加 render 成本)。selftest 新增 7 项回归(封顶/滚动跟随/CSV 失败自停/冻结
切片)共 59 项全过。整体审查报告(2026-10-12)其余 P3 遗留:selftest 未覆盖
_tick 主循环(超时清理/丢失判定)、"全部"窗口全量切片有 MAX_SAMPLES 兜底、
_last_set 单槽位罕见误补偿(8s 自愈)、build_exe remove_stale 无提示强杀
运行实例、M888 后固定 2s 重查可能早于固件就绪、_danger_reset 把去重忽略记成
"已下发"。协议建议的 300ms×3 自动重发维持不做(设计决策,用户拍板)。
- selftest 全过(累计新增 15 项回归用例,含窗口图标非空检查);exe 已本地
打包冒烟,Gitea 发布待用户确认后执行。
遗留见其 README"已知事项":USB-RS485 适配器更换。
- [x] **GUI 慢性卡顿修复(根因已定位并修复 v0.2.8,待真机确认)**:
根因/机理/实测数据见上方 v0.2.8 条目(`cursor.Start` 实例级枚举访问在
PySide6 6.11 必抛 → tick 异常中止 → 应答超时清理失效 + RX 积压 ratchet +
日志无限增长)。复现/验证脚本:`GUI/_diag_latency.py`(修复基线)/
`GUI/_diag_latency_buggy.py`(带 bug 对照,假固件 100ms 上报+定时点击)。
遗留:待真机长时间运行确认 + 重新打包 exe。
- [ ] **LED 引脚确认**:FilmForge 自制板 LED 引脚未定(当前沿用模板默认 PA15,
仅为构建占位),按原理图修改。
- [ ] **delay_10us 校准**:M4@168MHz 系数为估算值(/300000),需实测修正。
## 备注
- 本机凭据/发布约定见用户级 `C:\Users\Lenovo\.zcode\AGENTS.md`。
- 模板工程位置:`E:\Hulk-Coding\gd32f4xx_template_cmake_vscode`(模板对标工程,
Gitea: gd32f4xx_template_cmake_vscode)。
- E23x 工程位置:`E:\Hulk-Coding\gd32e23x_template_cmake_vscode`(协议/驱动参考)。