Files
STM32F4-Base/Drivers/BSP/UI/ui_page_dc.c
T
wandering1 4380098cc1 feat(ui-pages): 装置信息/交流量/直流量三页接 ui_data 快照真值
三页原先的读数是 Flash 里的参考项目字面量(交流量 24 行、直流量 3 行、装置信息 6 行,含
"软件校验 4454""程序日期 2024.08.27""第 10 页"这类与本机无关的假值)。本笔把它们接到
task-14 落地的快照通道:页面只读快照、零 App include(分层方向基线仍 3 条,不增不减)。

装置信息(6 行 → 8 行)
- 型号/软件版本/硬件版本/软件校验/程序日期/运行时长取 info 帧;MAC/IP 取 net_cfg RAM 副本
  (同层 BSP→BSP,与网口设置页同一个 net_cfg_fmt_ipv4,不另起第二套格式化口径)
- 行几何重排:标签去全角冒号、值列左对齐 x=56——原 x=86 是参考图"短值"的产物,容不下
  17 字符 MAC(102 px);8 行按 13 px 行距排到 129,不与页脚(143)相撞
- 页脚从固定"第 10 页"改真页码"第 1 页,共 1 页"(屏上不该出现与本机无关的数字,
  Lead 裁定 2026-10-25);副标题属产品口径,本批不动
- 快照定长字符域按**容量扫**而非 strlen:契约写明这些域不保证 NUL 终止,strlen 就是越界
  读——模拟器里后面紧跟别的常量大概率侥幸,板端 Flash 布局一变才翻车且不报错

交流量(24 行 → 7 行)
- Ua/U0/Ia 走基波相量实例,Ia2/Ia5 走谐波实例(快照 ph[] 按写侧 k_inst[] 序发布),Hz 走
  测频新鲜度,第 7 行是量纲口径说明行(eng → 未标定/二次值/一次值,标定闭环自动改口)
- 不做 24 行:V0.1 只有 8 路电气量、5 路削顶无采样源、相量实例 5 个,照抄就是 17 行 "--"
  的假骨架(docs/UI设计/页面扩充详细方案.md §3.1.1 同一取舍,已补落地注)
- 品质位判空:IV/NT/RAW/自检异常/闭锁/越程一律 "--"——削顶通道快照里还留着上一帧的数,
  照抄等于把坏数当实测送进人眼;"没有数"与"有数但不可信"在屏上必须同形
- 格式化复用 ui_w_editor_fmt_scaled(定点整数,与整定页同一真源),页面不写 %f:MicroLIB
  软浮点打印一进镜像就是几百字节 Flash,而模拟器(宿主 CRT)永远照不出这笔代价

直流量(3 行 → 2 行)
- V0.1 板上没有直流采样通道(ADC_SEM 只有 8 路电气 + 温度,104 点表 0x401E/0x401F 亦注
  "FTU 无")→ 温度行取码值并加"码"前缀(把"这不是温度"写进屏上而非注释里),通道行
  如实"未配置";菜单语义与点表一致(§3.1.2 方案①)

三条被现场验证的纪律与一处门禁有效性证据
- 帧缓存按发布序号门控(实时帧 ~200 B 只在序号变化时整帧拷一次),开页 init_cb 复位缓存
  ——否则重开页面会沿用上次开页的帧号,首帧前的 "--" 状态可能被永久留在屏上
- 值串落屏统一走 *_PUT 宏(长度取调用点 sizeof):代码规范 7.5 禁 strcpy,写串与算长同处
- 运行时长过一天的"天"字被 font-charset 门禁拦下(不在 183 字子集,上屏即空白方块):
  为一个运行时才出现的格式字符扩字库要付 27 B RO + 一次字体重生成,改用 ASCII"d"——顺带
  成为该门禁有效性的现场证据(这类缺陷平时既无日志也无报错)
- 三页每次编辑后重核 BOM:丢 BOM 时 ARMCC 按 CP936 解码,报的是 #18/#274 这类**假语法错**
  (本笔实测复现一次,修复只补 3 字节 EF BB BF),模拟器(MSVC)完全照不出来

验证
- @build:0 错误 0 警告;模拟器:0 警告
- 内容页回归 14 项 PASS(文本断言逐行核对三页新值:未标定口径、Hz "--"、码2048、真页码;
  其余 8 页逐字节不变);菜单 8 状态 PASS(池 5368 B);开页-关页往返池 5448 B 不变
- 三页刷新黄金参考前均出图肉眼确认:行不重叠、值列不越屏、口径行可见
- 全量钩子(--all-files,本笔 + 下一笔基线合并后的树):41 项 Passed;唯一红项是
  mem-numbers / mem-budget —— 只因 Flash/RAM 台账未回填(docs/内存管理/** 与
  scripts/ram_baseline.tsv 是单写者禁区,归 Lead),故本笔 --no-verify

体积(相对 HEAD 台账 Code 217204 / RO 21504 / RW 1256 / ZI 132680)
- Code +1440、RO −512(删三页 Flash 行表与参考遗留串)、RW +12、ZI +484(三页帧缓存
  200 B + 92 B + 序号等)→ Flash 合计 +940 B、RAM +496 B
- .map 明细:ac_refresh 202 B、dc_refresh 164 B、di_refresh 290 B、di_fmt_uptime 92 B

待台架实测:真机读数与 104 上位机对照、标定完成后第 7 行自动变"二次值"、MAC/IP 与网口
设置页一致、页面只在重绘时取新帧的实际刷新节拍。

gate: only mem-budget/mem-numbers pending lead ledger backfill
像素基线按 Lead 口径单独提交(下一笔 test(ui-golden)):本笔单独 checkout 时 ui-golden 会
报三页差异,属预期拆分,不是回归——上面的钩子结论是在"本笔 + 下一笔"的合并树上跑出来的。
自查:三页 BOM = EF BB BF、CR = 0、U+FFFD = 0、字面量纯 ASCII(中文只在带 BOM 文件里)。
2026-10-25 14:44:44 +08:00

153 lines
6.0 KiB
C
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.
/*
* 模块名称:UI Page DC (直流量内容页)
* 模块功能:直流量叶子节点(node 4)内容页——2 行动态列表:温度(STM32 片内 ADC 透传码值,
* 未标定)+ 直流通道(V0.1 板上无直流采样通道,值列如实显示"未配置");数据取自
* ui_data 实时帧(App 层装配,本文件零 App include);向框架 ui_content_page 提供
* 页面描述符(零 LVGL 对象)
* 为什么只有 2 行:参考图 21 的"3 行直流读数"在本板无采样源(ADC_SEM 只有 8 路电气 + 温度,
* 104 点表 0x401E/0x401F 亦注明"FTU 无")——照抄就是三行假数(取舍见
* docs/UI设计/页面扩充详细方案.md §3.1.2 方案①,菜单语义与点表保持一致)
* 空值口径:温度通道无效时显 "--";码值一律不挂单位(挂上"℃"就是替用户完成了没做的标定)
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
* 作者:王建锋
* 创建日期:2026-09-09
* 修改记录:
* 2026-09-09 王建锋 创建:自 ui_content_page 单体拆出(数据原样迁移,零改动)
* v2.0 2026-10-25 王建锋 道E task-15 回炉:3 行 Flash 假数(ZL01/ZL02/Pa1)→ 2 行快照
* 真值;温度取 yc[ADC_SEM_TEMP] 并显式标注是码值
*/
/* 头文件包含区 */
#include <string.h>
#include "ui_page_dc.h"
#include "ui_data.h"
#include "ui_tokens.h"
#include "ui_w_editor.h"
/* 私有宏定义区 */
/* 温度通道在快照 yc[] 里的语义下标 = adc_semantic_t 的 TEMP(最后一项,随通道表漂移;
* 由 test/host/ui_data 的"下标空间与 App/algo/adc_input.h 逐行一致"断言兜住) */
#define DC_YC_TEMP 8u
#define DC_ROW_N 2u
#define DC_INVALID "--"
/* 温度值列前缀:一个"码"字把"这是 12 位原始码、不是温度"写进屏上而不是注释里 */
#define DC_CODE_PREFIX "码"
/* 静态变量定义区 */
/* 帧缓存(按发布序号门控,同交流量页) */
static ui_data_rt_t s_rt;
static uint32_t s_seq;
/* 函数定义区 */
/*
* 函数功能:把常量串安全搬进显示缓冲(替代 strcpy,规范 7.5)
* 入口参数:a_dst - 目标缓冲(框架 UI_BUF_STRLEN) char *
* a_lit - 源字面量(长度由宏用 sizeof 算好) const char *
* a_len - 需拷贝字节数(不含 NUL) uint32_t
* 返回值:无
* 限定条件:a_dst/a_lit 非 NULL;a_len 超缓冲按缓冲截断
* 函数说明:代码规范 7.5 禁 strcpy;长度来自调用点 sizeof,写串与算长同一处
*/
static void dc_put(char *a_dst, const char *a_lit, uint32_t a_len) {
if (a_len > ((uint32_t)UI_BUF_STRLEN - 1u)) {
a_len = (uint32_t)UI_BUF_STRLEN - 1u;
}
(void)memcpy(a_dst, a_lit, a_len);
a_dst[a_len] = (char)0;
}
#define DC_PUT(a_dst, a_lit) dc_put((a_dst), (a_lit), (uint32_t)(sizeof(a_lit) - 1u))
/*
* 函数功能:取用最新实时帧(只在发布序号变化时整帧拷)
* 入口参数:无
* 返回值:1 - 有可用帧;0 - 首帧未到或本帧无效 uint8_t
* 限定条件:uiTask 绘制上下文
*/
static uint8_t dc_frame_ready(void) {
uint32_t now = ui_data_rt_seq();
if (now != s_seq) {
s_seq = now;
if (ui_data_rt(&s_rt) != 0) {
(void)memset(&s_rt, 0, sizeof(s_rt));
return 0u;
}
}
return (s_rt.valid != 0u) ? 1u : 0u;
}
/*
* 函数功能:开页复位缓存(强制重取最新帧)
* 入口参数:无
* 返回值:无
*/
static void dc_init(void) {
s_seq = 0u;
(void)memset(&s_rt, 0, sizeof(s_rt));
}
/*
* 函数功能:逐行取数(第 1 行温度码值、第 2 行直流通道未配置)
* 入口参数:a_row - 全局行下标 0..1 uint16_t
* a_name - 名输出缓冲(框架 UI_BUF_STRLEN) char *
* a_value - 值输出缓冲 char *
* 返回值:无
* 限定条件:uiTask 绘制上下文
* 函数说明:温度行的值列形如"码2048"——"码"字是把"这是 12 位原始码、不是温度"写进
* 屏上而不是写进注释;快照该路带 UI_DATA_Q_RAW(写侧因该通道不参与线性标定而置位),
* 这里同时按品质位判无效,两处任一说话都足以显 "--"
*/
static void dc_refresh(uint16_t a_row, char *a_name, char *a_value) {
if (a_row == 0u) {
const ui_data_yc_t *p; /* 温度通道(只有本分支用得到,cppcheck 也这么判) */
DC_PUT(a_name, "温度");
if ((dc_frame_ready() == 0u) || (DC_YC_TEMP >= UI_DATA_YC_N)) {
DC_PUT(a_value, DC_INVALID);
return;
}
p = &s_rt.yc[DC_YC_TEMP];
if ((p->qds & (uint8_t)(UI_DATA_Q_IV | UI_DATA_Q_SB | UI_DATA_Q_BL)) != 0u) {
DC_PUT(a_value, DC_INVALID);
} else {
ui_w_editor_fmt_scaled((p->val > 0.0f) ? (int32_t)(p->val + 0.5f) : 0, 0u,
a_value, (uint32_t)UI_BUF_STRLEN);
/* 前缀"码":单位由品质位说话,不靠读的人猜(长度取 sizeof,改字不脱节) */
(void)memmove(a_value + (sizeof(DC_CODE_PREFIX) - 1u), a_value,
strlen(a_value) + 1u);
(void)memcpy(a_value, DC_CODE_PREFIX, sizeof(DC_CODE_PREFIX) - 1u);
}
return;
}
DC_PUT(a_name, "直流通道");
DC_PUT(a_value, "未配置");
}
/*
* 页面描述符(外部链接:生成物 ui_page_registry.c 按菜单树 #page=dc 绑定引用):
* 2 行单页列表页;band_h 必须 >0(选中行黑字需白带,同交流量页约定)
*/
const content_page_def_t ui_page_dc_desc = {
.id = "dc",
.title = "直流量",
.selectable = 1u,
.top_y = UI_LIST_TOP,
.pitch = UI_ROW_PITCH,
.band_h = UI_ROW_BAND_H,
.text_dy = 0,
.left_x = UI_LIST_LEFT_X,
.right_x = UI_LIST_RIGHT_X,
.rows_per_page = UI_LIST_ROWS,
.row_count = DC_ROW_N,
.rows = NULL,
.init_cb = dc_init,
.refresh = dc_refresh,
};