EMS 知识库
首页 / knowledge/代码解析/midware/meter

backupbox.h

源文件路径:midware/meter/backupbox.h 所属模块:midware/meter(备电盒 / BackupBox 负载管理) 代码行数:50

1. 文件职责

本头文件定义备电盒(BackupBox)模块的两张表与唯一对外接口:BACKUP_BOX_CONFIG_T 保存用户可配的分相优先级与各相 SOC 门限,BACKUP_BOX_RUN_T 保存运行时各相开关状态、SOC 切出位图、上次下发命令位图、电网状态与过载计数。这两张表以「配置 + 运行」成对的形式被 midware/meter/meter.h 直接内嵌进 METER_TABLE_T(分别为 t_config_data.t_bb 与 t_bb_info,meter.h:397、meter.h:443),因此本头文件必须被 meter.h include(meter.h:17),成为电表模块的类型前置依赖。它只导出一个函数 bb_load_manage(),由 meter.c 的电表任务在检测到备电盒型号时调用。

2. 关键数据结构与宏

名称类型说明
__EMS_BACKUPBOX_H__宏头文件包含卫士(backupbox.h:10)
BB_DEBUG_INFO宏0(backupbox.h:20)。置 1 时 backupbox.c 会在每个状态迁移点打印 printf 调试信息,含各相开关、soc_offline、soc_offline_last
BACKUP_BOX_CONFIG_T结构体(backupbox.h:23)备电盒配置表:u8_enable(备电盒使能,0/1)、u8_prio_lx[3](L1/L2/L3 三相优先级,取值 2 或 3 表示该相可被过载切出)、u8_soc_lx[3](各相 SOC 门限,单位 %)、u32_sn(序列号)、u16_ver(备电盒固件版本)。未使用 #pragma pack,因此结构体长度依赖编译器默认对齐(u32_sn 会使尾部补齐)
BACKUP_BOX_RUN_T结构体(backupbox.h:33)备电盒运行表:<br>u8_state_lx[3] — 各相负载开关实际状态<br>u8_soc_offline — 因 SOC 被切出的相位位图(bit0=L1、bit1=L2、bit2=L3)<br>u8_soc_offline_last — 上一次位图,用于边沿去抖<br>u8_cmd_last — 上一次下发命令的 3 bit 位图(`(L3<<2)(L2<<1)L1)<br>u8_grid_state — 电网状态;等于 2 时表示需要以 u8_state_lx 为准刷新软件位图<br>u8_overload_flag[3] — 各相过载标志<br>s8_overload_cnt[3] — 各相过载计数器(单相逻辑用 3 次确认)<br>s16_power_lx[3] — 各相负载功率缓存<br>u8_bb_running_state — 备电盒运行/升级状态标记(meter.c:5740` 在 OTA 时置 FALSE)

注:backupbox.h 中没有任何位域、联合体或枚举定义;位图语义完全靠注释与 backupbox.c 中的移位表达式约定。u8_grid_state、u8_prio_lx 中「2」「3」等取值也没有配套的枚举/宏,是裸魔法值。

3. 函数清单

本文件为纯声明型头文件,不含任何函数定义。

函数名作用域说明
bb_load_manage全局(声明于 backupbox.h:47)备电盒负载管理唯一入口,实现在 backupbox.c:721

说明:backupbox.c 中另外两个非 static 函数 single_phase_bb_load_manage(backupbox.c:398)与 triphase_bb_load_manage(backupbox.c:656)没有在本头文件声明,属于「有外部链接但无对外契约」的状态——它们只被 bb_load_manage() 在文件内调用,本应加 static。

4. 核心逻辑解析

4.1 配置表与运行表的职责切分

表谁写谁读持久化
BACKUP_BOX_CONFIG_T(g_t_meter.t_config_data.t_bb)HMI 菜单 / 服务器下发(经 data/ 配置管理)backupbox.c 四个处理函数、single_phase_bb_load_manage、triphase_bb_load_manage是,随 METER_TABLE_T 的 config 区落 Flash
BACKUP_BOX_RUN_T(g_t_meter.t_bb_info)backupbox.c(u8_soc_offline/u8_soc_offline_last/u8_cmd_last/s8_overload_cnt/u8_overload_flag)、meter.c(u8_state_lx/u8_grid_state/u8_bb_running_state)backupbox.c、HMI 显示否,仅 RAM

这种「配置 + 运行」成对布局是 EMS 项目里 meter.h、logic.h 等的通行做法:METER_TABLE_T 把可持久化字段集中在 t_config_data 里,运行态字段放在外面,data/ 的保存作业只搬运 t_config_data。

4.2 位图语义(唯一的跨模块数据契约)

u8_soc_offline、u8_soc_offline_last、u8_cmd_last 三个字段都是 3 bit 位图,语义一致:

bit0 → L1 (state_lx[0])
bit1 → L2 (state_lx[1])
bit2 → L3 (state_lx[2])
值 = (state_lx[2] << 2) | (state_lx[1] << 1) | state_lx[0]

u8_cmd_last = 0x0F(在 backupbox.c:417、backupbox.c:680 被用作「无有效命令」的哨兵值,因为 bit3 永远为 0,0x0F 不可能是合法位图)与 u8_soc_offline = 0x07(三相全部被切出)是两个隐含的约定值,头文件里没有解释。

4.3 与 uCOS-II 的并发约定

本头文件不涉及同步原语。两个表都由 midware/meter/meter.c 的 task_meter 任务读写,而 bb_load_manage() 也在同一任务上下文被调用(meter.c:5432,位于 meter_data_read() 之后的同一轮循环内)。因此:

4.4 与型号判定的耦合

BACKUP_BOX_CONFIG_T / BACKUP_BOX_RUN_T 本身不携带型号,型号由 METER_TYPE_E(meter.h:148 附近)的 BACKUPBOX_5K / BACKUPBOX_10K / BACKUPBOX_23K 表达。本头文件不引用这些枚举值,但 backupbox.c 依赖它们来:

  1. 判断是否进入备电盒逻辑(meter.c:5428 与 backupbox.c:53)
  2. 决定是否有 change_state_bb_lx() 的下发动作

因此新增备电盒型号时需要同时改 meter.h 的 METER_TYPE_E、meter.c 的三处型号判断、backupbox.c:53 的型号判断,本头文件不需要改动。

5. 对外接口

本文件导出

名称类型使用者
bb_load_manage()函数原型midware/meter/meter.c:5432(task_meter)
BACKUP_BOX_CONFIG_T类型midware/meter/meter.h:397(t_config_data.t_bb)、backupbox.c
BACKUP_BOX_RUN_T类型midware/meter/meter.h:443(t_bb_info)、backupbox.c、HMI 显示层
BB_DEBUG_INFO宏backupbox.c(编译期裁剪调试打印)

本文件依赖的外部声明

chip.h(u8/s8/u16/u32 基础类型定义)。

6. 依赖关系

依赖

被依赖

7. 备注与风险点

  1. 两个外部链接函数未在头文件声明:single_phase_bb_load_manage()(backupbox.c:398)与 triphase_bb_load_manage()(backupbox.c:656)没有原型,也没有 static。它们目前只被 bb_load_manage() 调用,但外部模块若想调用会缺少类型检查(C 语言隐式声明在 C99 下只是警告)。建议加 static。
  2. BACKUP_BOX_CONFIG_T 未加 #pragma pack(1)(backupbox.h:23-backupbox.h:31):该结构体属于 METER_TABLE_T.t_config_data,是要落 Flash 并带 CRC 的结构。默认对齐下不同编译器/优化选项的填充字节数若发生变化,会导致 Flash 上旧数据的 CRC 校验失败。EMS 其它持久化结构体(如 ct.h 中的 CT_CONFIG_TABLE_T)都用了 pack(1),这里是不一致的做法,值得核实。
  3. 魔法值没有常量:u8_grid_state == 2(backupbox.c 中 6 处)、u8_prio_lx[i] == 2 || == 3(backupbox.c:136、backupbox.c:288)、u8_cmd_last == 0x0F、u8_soc_offline == 0x07、SOC 死区 +10、过载系数 0.8、恢复延时 1000*10 全部是裸数字。头文件里没有任何对应的宏或枚举,阅读与修改成本高。
  4. u8_bb_running_state 语义模糊:字段名与注释(meter.c:5740 的「BB升级状态认为停止运行」)不一致 —— 顾名思义是「运行状态」,实际当「是否正在升级」用。建议改名为 u8_bb_upgrading。
  5. u8_state_lx[3] 与 u8_cmd_last 可能长期不一致:u8_state_lx 由电表应答解析写入,u8_cmd_last 由备电盒逻辑写入,两者只有在 u8_grid_state == 2 时才会被强制对齐(backupbox.c:100-backupbox.c:108)。若备电盒固件从未上报 u8_grid_state == 2,软件位图会一直独立演化。
  6. s16_power_lx[3] 被 meter.c 写入但 backupbox.c 从不读取:写入点是 midware/meter/meter.c:3419-meter.c:3421(把 GRID 三相有功存进来,s32 → s16 截断),meter.c:3448-meter.c:3450 还会取反。而 backupbox.c 的四种处理函数算功率用的是各自的函数栈变量(l_s32_load_power / l_s32_powerload[3]),完全不读这个字段。也就是说「运行表里的分相功率」与「负载管理实际用的分相功率」是两个数据流,且前者存在 s16 截断(超过 ±32767 W 会回绕)。
  7. u32_sn / u16_ver 只由 meter.c 使用:backupbox.c 完全没读这两个字段;实际使用者是 midware/meter/meter.c:4493-meter.c:4511(与备电盒应答里的 u32_bb_sn / u16_bb_ver 比对并按变化写回)、meter.c:6161、meter.c:6191、meter.c:6343、meter.c:6359、meter.c:6394、meter.c:6405(拼装 SN 字符串与 V%u.%02u 版本号,用于上报/显示)。它们名为备电盒字段其实是「电表信息」复用,字段归属与使用者跨文件,改动时容易漏。
  8. u8_enable 的语义混合:它同时出现在备电盒逻辑(backupbox.c:446、backupbox.c:701)和功能开关位(midware/auxiliary/system_aux.c 里的 u8_bb_load_manage / u8_bb_load_management 是另一套功能位域)。两处开关分属不同机制,容易混淆谁才是真正的总开关。