4.1 KiB
4.1 KiB
待机恢复与时间 / 电量状态栏
当前实现(2026-10-09)以本文为准,旧 lcd-expressions.md 中的测试图案、 优先级仲裁描述不代表当前运行行为。
返回待机
- 开机 / 默认空闲、显式 IDLE 请求、有限动画 return_to_idle、缺失素材回退和 非取消的播放错误都进入同一个待机后端。
- CONFIG_TQ_LCD_EMOTE_GFX_TEST 启用且初始化成功时使用单纹理网格眨眼; 禁用或初始化失败才使用历史三帧 PNG 安全后备。
- 历史 jichubiaoqing 请求(duration_ms=0)也适配到 GFX。 有限播放保留 repeat_count,每轮为 frame_ms 睁眼停留 + 12 个 34ms 眨眼步骤; 不承诺与旧 PNG 完全相同的持续时间。服务错误因此不再临时退回三帧。
- 自动恢复只在没有 pending 请求且未停止时排入 IDLE,不能覆盖新来的请求。
- 其他表情仍为 PNG / step sequence,未改动其图像或动画顺序。 pending 仍是单槽替换,不是完整优先级状态机。
状态栏
- 左上 HH:MM,沿用 SNTP 和系统时区;未同步显示 --:--。
- 右上百分比和电池;未知值显示 --%,充电绿色并带闪电缺口,低电量红色。
- SOC、有效性和充电状态来自现有 domain battery 服务,不从 ADC 重算。
- GFX 顶部 320x40 RGB565 图层,常驻 25,600 B PSRAM;只在分钟或电池状态 改变时使图层失效并刷新,眨眼主要改变眼睛网格,接近闭合时切换为程序绘制的抗锯齿弧线,不解码新 PNG。
- PNG 表情复用相同点阵 / 电池绘制器,在每帧合成时更新;二维码和 LCD 边界测试页面不显示状态栏。PNG 无限等待期间不会独立重绘状态栏。
- 不需要字体包或新图片。旧 PNG 低电量底部告警保留;旧充电 PNG 不再自动 叠加,避免与数字电量冲突。GFX 待机低电量以红色电池表示。
验证
python3 tools/test_lcd_status_hud.py 从实际源码提取绘制函数,用 Clang
AddressSanitizer / UndefinedBehaviorSanitizer 检查 808 组有效性、充电、
低电量、0..100% 组合,验证行块和整帧等价、边界及颜色。
使用 ESP-IDF v5.5.4 执行 idf.py build。实机需验证:
- 联网后 --:-- 变成本地时间,跨分钟更新;未同步不显示伪造时间。
- 插拔充电线、电量变化时状态更新,眼睛位置 / 眨眼无变化或残影。
- 各有限动画、Wi-Fi 恢复、PTT 结束、OTA 退出及服务错误后回 GFX 待机。
- 动画结束同时到达新请求时不被自动 IDLE 覆盖。
编译 / 主机测试不等同于上述实机验证。
无 TE 的软件减撕裂试验
- GFX 使用单个 153,600 B PSRAM 合成缓冲(partition 模式,不是 RGB 全帧模式),
- 普通眼睛更新先完成整个 dirty 区域,再进入 flush;不会在分块传输之间计算网格。 +- flush 使用单个 10,240 B 内部 DMA 暂存区;按最多 5,120 像素连续搬运,
- 每批等待 ISR 完成后才复用,整区域发完才通知 GFX。PNG 原有 8 行块不变。 +- 相对上一版移除 2×2,560 B DMA 小缓冲,增加 5,120 B DMA 暂存净容量
- (不含 SPI 驱动描述符);新增合成缓冲和 9,996 B 闭眼纹理共 163,596 B PSRAM。 +- closure >=232 时隐藏压缩眼圈并显示同色的抗锯齿闭眼弧线,避免极薄纹理抖动。 +- 34ms 帧预算包含绘制/传输时间,超时不会再固定额外等 34ms。 +- 每轮日志 emote blink composed draw_us_avg=... late_frames=.../12,
- 仅反映绘制预算,不是面板实际扫描帧率。 +- DMA 超时会锁住 GFX 传输路径,不复用可能仍被硬件读取的缓冲;需重启恢复。 +- 此方案不能保证面板扫描无撕裂。实机比较眨眼上下断层、闭眼亮点及原有
- 表情切换/状态栏行为;无 TE 时不能把软件预合成称为硬件同步双缓冲。
主机传输/闭眼回归:python3 tools/test_lcd_emote_transport.py,检查 320 种
区域宽度、DMA 分块/数据顺序、错误/超时处理及闭眼对称性。当前 RTOS tick
为 10ms,实际眨眼间隔仍有 tick 量化及任务调度抖动,日志不是实测 FPS。