fault_warn_log.c
save_error_log_data,fault_warn_log.c:459)4.3 缓存批量落盘4.4 地址三元冗余与表决(error_log_data_addr_restore,fault_warn_log.c:107)4.5 上传打包与帧格式4.6 LCD 故障码 FIFO4.7 显示掩码打包(package_display_error_code,fault_warn_log.c:1936)4.8 Flash 擦除(erase_error_log,fault_warn_log.c:1604)4.9 历史查询地址计算(get_history_error_log_data,fault_warn_log.c:1703)4.10 EEPROM 与加热标志5. 对外接口导出的函数(供谁调用)导出的全局变量调用的外部函数/变量6. 依赖关系依赖被依赖7. 备注与风险点源文件路径:
data/fault_warn_log/fault_warn_log.c所属模块:数据管理 / 故障告警日志(data/fault_warn_log) 代码行数:2171
1. 文件职责
本文件是 EMS 的"故障/告警全生命周期记录器":以固定的采样快照差分方式,把 EMS、BMS、逆变器(PCS)、充电桩(EVC)、电表/BB 箱的故障位、告警位、保护位的变化翻译成带时间戳的故障码记录,写入 SPI Flash 环形区(ERROR_LOG_DATA_RECORD_ADDR ~ ERROR_LOG_DATA_RECORD_END)。它同时承担三条下游通路:打包成 CSV 帧通过 STATUS_SEND_ERROR_LOG 上传云平台(net/ems.c:6085)、把最近 10 条记录喂给 LCD 历史故障界面(hmi/ui/ui_history_error_log.c)、把故障位合并成 3 个 32 位掩码供 LED/主界面显示(hmi/led.c:831)。文件还维护 LCD 主界面滚动故障码 FIFO、EEPROM 读写故障标志、电池加热故障标志等辅助状态。它由 data/data.c:251 的 task_system_data 任务驱动,每轮循环调用一次 error_log_data_handle()。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
FAULT_CODE_PAIR_T | 结构体 | {u16 faultBitPos; u32 fault_code;},把"位域里的第 N 位"映射到"对外故障码",是所有差分扫描表的元素类型 |
ERROR_DEVICE_TYPE_E | 枚举 | 设备类型:ERROR_NONE / ERROR_EMS / ERROR_INV / ERROR_BMS / ERROR_EVC / ERROR_METER |
ERROR_TYPE_E | 枚举 | 事件类型:NONE_TYPE / WARN_CLEAR / FAULT_CLEAR / WARN_OCCURRED / FAULT_OCCURRED / INFO_OCCURRED / PROTECTION_CLEAR / PROTECTION_OCCURRED |
ERROR_CODE_E | 枚举 | 全部对外故障码常量:E0000~E0094(EMS)、I10000~I10002(EMS 事件)、E60000~E60031(BMS)、W70000~W70015、P75000~P75009、P77500~P77532、E100000~E100456(INV)、W110000~W110137(INV 告警)、E200000~E200031(EVC)、E160000~E160002(METER) |
BMS_DISPLAY_ERROR_U | 联合体 | u32 u32_all 与 6 个 BMS 显示位(u8_bms_lost、u8_circuit_breaker_open、u8_dial_switching_mode_inconsistence、u8_slave_battery_communication_lost、u8_master_battery_communication_lost、u8_multi_master_error)叠加 |
INV_DISPLAY_ERROR_U | 联合体 | 25 个逆变器显示位(u8_inv_lost、u8_grid_ovp/uvp/ofp/ufp、u8_bus_ovp1、u8_insulation_fault、u8_gfci_fault、u8_para_*、u8_grid_loss_fault 等)叠加 u32_all |
ACCESSORIES_DISPLAY_ERROR_U | 联合体 | 附件/充电桩显示位(u8_grid_meter_lost、u8_pv_meter_lost、u8_evchargerlost、u8_relay_otp、u8_output_overload、u8_ac_leakage_current、u8_input_terminal_otp、u8_relay_abnormal、u8_ground_fault、u8_reverse_phase、u8_afci_*)叠加 u32_all |
STORE_ERROR_LOG_ADDR_T | 结构体 | 地址备份单元,#pragma pack(1) 共 16 字节:u32_log_send_addr、u32_log_save_addr、u16_flash_idex、u8_reserve[4]、u16_crc_code;4096/16 = 256 个单元恰好占满一个 Flash 扇区 |
STORE_ERROR_LOG_DATA_T | 结构体 | 单条故障日志,#pragma pack(1) 共 32 字节:Time(6)、u8_device_type、u8_fault_or_warn、u8_fault_location、u8_fault_id、u32_fault_code、s32_fault_value、u8_reserve[12]、u16_crc_code |
ERROR_LOG_TABLE_T | 结构体 | 模块总上下文,约 17.5KB,放在 SDRAM(SDRAM_FAULT_LOG_START_ADDR,预留 20K)。含 4KB 扇区临时缓冲、各设备本地位域快照、地址结构、256 条写缓存、256B×5KB 上传缓冲、3 个显示掩码、BB 箱故障 |
ERRCODE_FIFO_T | 结构体 | LCD 主界面故障码 FIFO:u8_error_code_level_judgment_flag、u8_lcd_show_buf_len、u8_errcode_Write(写指针=当前有效条数)、u32_errcode_buf[10] 环形缓冲 |
BIT_SET / BIT_CLEAR / BIT_IS_SET / BIT_VALUE | 宏 | 按位索引读写字节数组:BIT_VALUE(byteData,i) 取第 i 位值;BIT_IS_SET(byteData,i) 判断是否为 1 |
ERROR_LOG_DATA_CACHE_MAX_SIZE | 宏 | 256,写缓存条数上限(注释提醒"缓存不能超过 65535") |
ERROR_LOG_SERVER_PACK_MAX_SIZE | 宏 | 5*1024,单包上传缓冲上限 |
ERROR_LOG_DATA_RECORD_ADDR_BACKUP1/2/3 | 宏 | 0xF63000 / 0xF64000 / 0xF65000,地址三元冗余备份扇区 |
ERROR_LOG_DATA_RECORD_ADDR / _END | 宏 | 0xF66000 / 0xFC8FFF,日志数据环形区(约 396KB) |
ERRCODE_FIFO_SIZE | 宏 | 10,LCD 故障码缓冲深度 |
DEBUG_FLASH_DATA_STORE | 宏 | 0,日志调试打印总开关(注意与 flash_data_store 里的同名宏重复定义) |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
error_log_data_init | 全局 | 清零 g_t_error_log_tab,调用地址恢复,把临时发送地址对齐到已恢复的发送地址 |
error_log_data_addr_save | 全局 | 重算地址结构 CRC 并写入 3 个备份扇区,然后递增 u16_flash_idex(0~255 环回) |
error_log_data_addr_restore | static | 从 3 个备份扇区各取最后一个合法记录,两两比对表决出地址,并补写一次地址 |
save_error_log_data_to_flash | 全局 | 把缓存数组按 32B/条写入 Flash,处理越界回绕并调整发送指针 |
save_error_log_data_to_cache | 全局 | 把一条故障写进 RAM 缓存并刷新 LCD 故障码 FIFO,满 256 条或收到 ERROR_NONE 时刷入 Flash |
save_error_log_data | 全局 | 核心差分扫描函数:重启/按键事件 + EMS/BMS/保护/BMS 告警/INV/INV 扩展/INV 告警/EVC/EVC-II/BB 箱共 13 组位域扫描 |
get_error_device_type_string | 全局 | 设备类型枚举 → CSV 字段(System/PCS/BMS/EVC/NONE) |
get_error_device_subtype_string | 全局 | 设备类型枚举 → 子类型字符串(ems/dcac/lmu/evc/NONE) |
get_error_state_string | 全局 | 事件类型 → clear/occur/NONE |
get_error_level_string | 全局 | 事件类型 → Warning/Protection/Fault/Info/NONE |
pack_error_log_data_end | static | 给上传缓冲补 7 字节帧头(EMS+REQUEST_COMM+CMD_UPDATE_ERROR_LOG+4 字节长度)与 Modbus CRC |
upload_error_log_data_package | 全局 | 打包待上传故障日志成 CSV 帧;同时处理发送成功后的发送指针确认(ACK)分支 |
error_log_data_handle | 全局 | 模块总入口:采集→上传→LCD 历史查询,并每轮调用 package_display_error_code |
set_error_log_data_send_ok_true | 全局 | 云平台确认收到日志后置 ACK 标志、清发送标志与发送长度 |
erase_error_log | 全局 | 擦除 0xF63000~0xFC8FFF 全区间(块+首尾零头扇区),按 3 次重试并喂看门狗 |
error_log_data_clear | 全局 | 工厂复位用:整体清零上下文、擦除日志区、重置地址并保存 |
get_history_error_log_data | 全局 | 从保存指针往前读最多 len(≤50)条日志,CRC 校验后填入 g_t_history_error_log[],返回有效条数 |
put_errcode | static | 向故障码 FIFO 压入一个故障码(去重;满 10 条则整体前移丢弃最旧) |
release_errcode | static | 从故障码 FIFO 中移除一个故障码并压缩数组 |
lcd_get_errcode_buf_len | 全局 | 返回 FIFO 当前有效条数,同时刷新"故障码变化"判定标志 |
lcd_get_errcode_buf_judgment_flag | 全局 | 比较条数与登录界面状态,设置 u8_lcd_error_code_judgment_flag |
get_show_errcode | 全局 | 按偏移读 FIFO 中一个故障码,空则返回 0 |
update_lcd_mainui_app_show_error_code | static | 仅对 FAULT_OCCURRED/FAULT_CLEAR 生效,分别调用 put_errcode/release_errcode |
package_display_error_code | static | 把各设备原始故障位与跨簇"或"运算合并成 BMS/INV/附件三个显示掩码 |
get_bms_display_error_code | 全局 | 返回 u_bms_display_error.u32_all |
get_inv_display_error_code | 全局 | 返回 u_inv_display_error.u32_all |
get_accessories_display_error_code | 全局 | 返回 u_accessories_display_error.u32_all |
set_eeprom_fault_flag | 全局 | 按 EEPROM 页号在 32 位掩码中置/清对应位(页范围 SYSTEM_STARTE_PAGE~SYSTEM_DATA_BACKUP_PAGE 之外直接返回) |
get_eeprom_hardware_read_fault_flag | 全局 | 返回硬件读故障掩码指针 |
get_eeprom_hardware_write_fault_flag | 全局 | 返回硬件写故障掩码指针 |
get_eeprom_software_read_fault_flag | 全局 | 返回软件读故障掩码指针 |
get_eeprom_software_write_fault_flag | 全局 | 返回软件写故障掩码指针 |
set_bat_heat_fault_flag | 全局 | 置/清 g_t_ems_info.u_ems_fault.bit.u8_bat_heat_fault |
read_bat_heat_fault_flag | 全局 | 读电池加热故障位 |
4. 核心逻辑解析
4.1 调度入口与时序
error_log_data_handle()(fault_warn_log.c:1538)是唯一入口,被 data/data.c:294 的 task_system_data 调用。调用点位于 OSSemPend(g_t_power_down_sem, 500, &err) 超时分支(err != OS_ERR_NONE),即掉电信号量未在 500 tick 内到来时执行——因此扫描周期约为 500ms。
处理流程:
IsDownloadEMS()为真(正在升级 EMS 固件)时整段跳过,只执行最后的package_display_error_code()。save_error_log_data()做全量差分扫描。- 仅在
g_stEMSInfo.bIsLogin && g_stEMSInfo.bIsBuiltSocket == TRUE时调用upload_error_log_data_package();否则强制u8_error_log_send_flag = FALSE(断开时不保留半包)。 - LCD 历史查询:用
g_u8_get_history_error_log_flag做一次性初始化,之后每3*60*1000tick(约 3 分钟)用OSTimeGet()差值判断刷新一次;OSTimeGet() - tick为负数(时钟回绕或已刷新)时直接把 tick 拉平,避免长时间不再刷新。
4.2 快照差分扫描状态机(save_error_log_data,fault_warn_log.c:459)
这不是传统状态机,而是"位域镜像差分"机制:g_t_error_log_tab 中为每类故障保存一份上一周期的位域镜像,与实时全局变量比较后产生事件,最后把整份镜像更新为新值。
差分的通用判定(以 EMS 为例,fault_warn_log.c:551-563):
if (BIT_VALUE(镜像, bitPos) != BIT_VALUE(实时, bitPos)) {
if (BIT_IS_SET(实时, bitPos)) → save_error_log_data_to_cache(..., FAULT_OCCURRED, ..., code);
else → save_error_log_data_to_cache(..., FAULT_CLEAR, ..., code);
}
镜像.u32_all = 实时.u32_all;
各组扫描对象、镜像变量与实时来源:
| 组 | 镜像(旧) | 实时(新) | 事件类型 | 故障码区间 |
|---|---|---|---|---|
| EMS 故障 | u_ems_err_log | g_t_ems_info.u_ems_fault | FAULT_OCCURRED/CLEAR | E0001~E0094 |
| BMS 故障(簇 0~12) | u_bms_fault_log[i] | g_t_bat_info.t_run_info.u_bms_fault_code[i] | FAULT_OCCURRED/CLEAR | E60000~E60029 |
| BMS 保护(簇 0~12) | u_bms_protection_log[i] | u_bms_protection_code[i] | PROTECTION_OCCURRED/CLEAR | P75000~P75008 |
| BMS 保护扩展 1 | u_bms_protection_extend1_log[i] | u_bms_protection_extend1_code[i] | 位序号直接决定事件类型 | P77500 + j |
| BMS 保护扩展 2 | u_bms_protection_extend2_log[i] | u_bms_protection_extend2_code[i] | PROTECTION_OCCURRED/CLEAR | P75009(动力线过温) |
| BMS 告警(簇 0~12) | u_bms_warn_log[i] | u_bms_warning_code[i] | WARN_OCCURRED/CLEAR | W70000~W70015 |
| INV 故障 | u_inv_fault_log | g_t_inv_info.t_run_info.u_fault_code | FAULT_OCCURRED/CLEAR | E100000~E100062、E100140 |
| INV 故障扩展 1 | u_inv_fault_extend1_log | u_fault_extend1_code | FAULT_OCCURRED/CLEAR | E100122~E100403 |
| INV 故障扩展 2 | u_inv_fault_extend2_log | u_fault_extend2_code | FAULT_OCCURRED/CLEAR | E100404~E100456 |
| INV 告警 | u_warning_code | u_warning_code | WARN_OCCURRED/CLEAR | W110000~W110103 |
| INV 告警扩展 1 | u_warning_extend1_code | u_warning_extend1_code | WARN_OCCURRED/CLEAR | W110108~W110137 |
| EVC(一体桩) | u_evc_fault_u | g_t_evc_run_info.evc_fault_u | FAULT_OCCURRED/CLEAR | E200000~E200031 |
| EVC-II(4 路) | u_evc_ii_fault_u[i] | g_t_evc_ii_run_info[i].evc_ii_fault_u | FAULT_OCCURRED/CLEAR | E200000~E200031,fault_location = i+1 |
| BB 箱 | u_bb_fault_u | g_t_meter.t_bb_debug.bb_fault_u | FAULT_OCCURRED/CLEAR | E160000~E160002 |
两个特殊分支:
- 重启信息:静态变量
s_u8_restart_flag初值为TRUE,首次进入即上报I10000(fault_warn_log.c:466-470),即"本机开机"事件。 - LED 按键长按:对
LED_BUTTON做 0~3 计数(按住递增、松开递减),计数值从非 3 变为 3 时上报I10002(INFO_OCCURRED),从非 0 变为 0 时上报I10002的WARN_CLEAR(fault_warn_log.c:472-512)。
BMS 保护扩展 1 的事件类型判定比较特殊(fault_warn_log.c:657-688):位序号 P77500 + j 若命中硬编码集合 {P77501, P77504, P77505, P77510, P77514, P77516} 则记为 FAULT,否则记为 PROTECTION。
函数末尾(fault_warn_log.c:1233)用 save_error_log_data_to_cache(ERROR_NONE, NONE_TYPE, 0, 0, E0000) 作为"刷盘哨兵"。
4.3 缓存批量落盘
save_error_log_data_to_cache(fault_warn_log.c:421):
device_type == ERROR_NONE:把t_error_log_data[0]起count条整体写入 Flash,然后清零计数。- 否则填
Time = SYSTEM_DATETIME、设备/类型/簇号/ID/故障码,逐条算GetCrcCode_Modbus(..., sizeof(STORE_ERROR_LOG_DATA_T) - 2)存入u16_crc_code,计数 +1 并调用update_lcd_mainui_app_show_error_code;计数达到 256 时立即整体落盘。
save_error_log_data_to_flash(fault_warn_log.c:319)的写入与回绕:
若 save_addr + len > ERROR_LOG_DATA_RECORD_END:
secremain = (END+1 - save_addr) - (END+1 - save_addr) % 32 // 向下取整到 32B 边界
先写 [save_addr, +secremain),再写 [RECORD_ADDR, +剩余长度)
save_addr = RECORD_ADDR + 剩余长度
否则:
直接写,save_addr += len
随后是一段"发送指针追赶"逻辑(fault_warn_log.c:364-409),等价语义是:
- 如果本次写入没有跨越回绕点(
旧 save_addr < 新 save_addr)而发送指针又落在(旧 save_addr, 新 save_addr]区间内,说明发送指针所指的数据已被覆盖,把发送指针推到下一个 4K 扇区起始地址((FLASH_ADDR_TO_SECTOR(save_addr)+1) * FLASH_SECTOR_SIZE),若越过ERROR_LOG_DATA_RECORD_END则回绕到ERROR_LOG_DATA_RECORD_ADDR。 - 若发生回绕(
旧 save_addr >= 新 save_addr),则只在发送指针"未领先"时同样前推到下一扇区。
每次写完都调用 error_log_data_addr_save() 落盘地址。
4.4 地址三元冗余与表决(error_log_data_addr_restore,fault_warn_log.c:107)
- 3 个备份扇区(各 4096B / 16B = 256 槽)逐个扫描,遇到第一个"非法"槽(
u32_log_send_addr或u32_log_save_addr不在[RECORD_ADDR, RECORD_END),或u16_flash_idex >= 256)就读前一个槽(fault_warn_log.c:131-143);即"最后一条合法记录 = 第一个非法槽的前一槽"。 - 每条记录再校验 Modbus CRC,失败则用
{RECORD_ADDR, RECORD_ADDR, 0}兜底。 - 三个扇区结果两两比对
(send_addr, save_addr, flash_idex)三元组,任一对相同即采纳;三份都不同则回落到初始值(fault_warn_log.c:261-290)。 - 表决结果若不是初始值,
u16_flash_idex++后按 256 环回(fault_warn_log.c:292-306),从而实现"每次保存写下一个槽",等价于 256 槽的地址日志轮转。
error_log_data_addr_save(fault_warn_log.c:66)反向操作:算 CRC,分别写到三个备份区的第 u16_flash_idex 槽(各重试 3 次),最后 u16_flash_idex++ 并按 256 环回。
4.5 上传打包与帧格式
upload_error_log_data_package(fault_warn_log.c:1397)有两个分支:
ACK 分支(u8_error_log_send_ok_flag == TRUE):set_error_log_data_send_ok_true()(由 net/server.c:6749 在收到平台回执时调用)已置位。此时把"上一次打包时记下的 u32_error_log_addr_temp"与当前发送指针做一致性比对,决定是否把 u32_log_send_addr 前推并重新保存地址;三个子分支覆盖"发送地址已回绕 / 未偏移 / 已偏移但 Flash 未填满"三种情形(fault_warn_log.c:1409-1444)。
打包分支:从 u32_error_log_addr_temp 一直读到 u32_log_save_addr(环形,越过 ERROR_LOG_DATA_RECORD_END 回绕到 ERROR_LOG_DATA_RECORD_ADDR),每条先 Flash_Read 3 次并校验 Modbus CRC,通过后才拼 CSV。
CSV 内容:
SN,Time,type,subtype,id,Code,state,level\n ← 首行,仅在 send_len == 0 时添加
<SN>,20YY/MM/DD HH:MM:SS,<type>,<subtype>,<fault_id>,<fault_code>,<state>,<level>\n
其中 type = get_error_device_type_string(u8_device_type)、state = get_error_state_string(u8_fault_or_warn)、level = get_error_level_string(u8_fault_or_warn)。
帧头(pack_error_log_data_end,fault_warn_log.c:1367):
| 偏移 | 长度 | 内容 |
|---|---|---|
| 0 | 1 | EMS(net/ems.h 中的设备地址宏) |
| 1 | 1 | REQUEST_COMM = 0x01 |
| 2 | 1 | CMD_UPDATE_ERROR_LOG = 0x0F |
| 3 | 4 | 大端 32 位数据域长度 = u32_error_log_send_len - 7 |
| 7 | N | CSV 文本 |
| 7+N | 2 | CRC16-Modbus,高字节在前 |
u32_error_log_send_len + N + 2 > 5120 时截断成当前包(fault_warn_log.c:1499)。
4.6 LCD 故障码 FIFO
update_lcd_mainui_app_show_error_code(fault_warn_log.c:1893)只处理 FAULT_OCCURRED/FAULT_CLEAR,分别对应 put_errcode(去重压入,满 10 条则整体左移淘汰最旧,fault_warn_log.c:1785-1798)与 release_errcode(把匹配项之后的元素左移压缩,fault_warn_log.c:1817-1830)。
lcd_get_errcode_buf_len 每次读长度时都调用 lcd_get_errcode_buf_judgment_flag,后者在"长度变化"或"登录界面 id_setting_into_last 变化"时置 u8_lcd_error_code_judgment_flag = TRUE,供 hmi/ui/ui_main.c:453 决定是否重绘主界面故障码区。
4.7 显示掩码打包(package_display_error_code,fault_warn_log.c:1936)
每轮 error_log_data_handle 末尾无条件调用(含升级期间),把多簇原始位做跨簇"或":
- BMS:
u8_bms_lost直接取 EMS 位u_ems_err_log.bit.u8_bms_lost;其余 5 位对u_bms_fault_log[0..6](硬编码 7 簇)逐位相或。 - INV:单机故障位直接映射;并机类位来自
u_inv_fault_extend1_log,u8_grid_loss_fault来自u_inv_fault_extend2_log。 - 附件:
u8_evchargerlost、u8_relay_otp、u8_output_overload、u8_ac_leakage_current、u8_input_terminal_otp、u8_relay_abnormal、u8_ground_fault、u8_reverse_phase为u_evc_fault_u与u_evc_ii_fault_u[0..3](硬编码 4 路)相或;u8_afci_self_check_fail取 EMS 位,u8_afci_arc_drawing_fault取 INV 扩展 2 位。
结果供 hmi/led.c:831/857/859/892/894 与主界面使用。
4.8 Flash 擦除(erase_error_log,fault_warn_log.c:1604)
先算出区间首尾包含整块的地址,然后分三段擦:块前的零头扇区(Flash_Erase_Sector)、中间整块(Flash_Erase_Block,64KB)、块后的零头扇区,每步最多重试 3 次并 IWDG_Feed()。error_log_data_clear(fault_warn_log.c:1685)在擦除前整体 memset 上下文,擦除后重置地址三要素并重新保存。
4.9 历史查询地址计算(get_history_error_log_data,fault_warn_log.c:1703)
len 限定在 (0, 50]
起始地址 = save_addr - 32*len
若起始地址 < ERROR_LOG_DATA_RECORD_ADDR:
起始地址 = ERROR_LOG_DATA_RECORD_END - (ERROR_LOG_DATA_RECORD_ADDR - 起始地址) // 环形回绕
逐条 +32 读取并 CRC 校验;u8_fault_or_warn != 255 才算"有效条数"
4.10 EEPROM 与加热标志
set_eeprom_fault_flag(fault_warn_log.c:2075)用 1 << (addr - SYSTEM_STARTE_PAGE) 把 EEPROM 页号映射到 32 位掩码(SYSTEM_STARTE_PAGE = 4071、SYSTEM_DATA_BACKUP_PAGE = 4095,恰好 25 页)。4 个 get_eeprom_*_fault_flag 返回各自静态掩码的地址,由 hardware/flash/feeprom.c、data/system_config/system_config.c、data/data.c 多处读写。set_bat_heat_fault_flag/read_bat_heat_fault_flag 直接操作 g_t_ems_info.u_ems_fault 的 u8_bat_heat_fault 位,由 midware/bms/bms.c 与 midware/inverter/set/set_comm_can.c 使用。
5. 对外接口
导出的函数(供谁调用)
| 函数 | 主要调用方 |
|---|---|
error_log_data_init | data/data.c:259(task_system_data 初始化) |
error_log_data_handle | data/data.c:294 |
error_log_data_clear | data/data.c:99(工厂复位) |
set_error_log_data_send_ok_true | net/server.c:6749 |
get_history_error_log_data | data/fault_warn_log/fault_warn_log.c:1556(自用)、LCD 历史界面 |
get_show_errcode | hmi/ui/ui_main.c:479/484/491、net/ems.c:850 |
lcd_get_errcode_buf_len | hmi/ui/ui_main.c:465/471/574 |
get_bms_display_error_code | hmi/led.c:831/857 |
get_inv_display_error_code | hmi/led.c:859/892 |
get_accessories_display_error_code | hmi/led.c:245/630/894/920 |
set_eeprom_fault_flag | hardware/flash/feeprom.c、data/system_config/system_config.c、data/data.c |
get_eeprom_hardware_read/write_fault_flag | hardware/flash/feeprom.c、data/data.c |
get_eeprom_software_read/write_fault_flag | data/system_config/system_config.c、data/data.c |
set_bat_heat_fault_flag | midware/bms/bms.c:1828/2306/2455/2611 |
read_bat_heat_fault_flag | midware/inverter/set/set_comm_can.c:211 |
导出的全局变量
g_t_error_log_tab(fault_warn_log.c:27,声明于fault_warn_log.h:703,定位在SDRAM_FAULT_LOG_START_ADDR):被hmi/led.c、hmi/ui/ui_history_error_log.c、net/ems.c、hmi/ui/ui_main.c直接访问。g_t_history_error_log[50]、g_u8_get_history_error_log_flag(fault_warn_log.h:704-705)。u8_lcd_error_code_judgment_flag(fault_warn_log.c:30,未在头文件声明,hmi/ui/ui_main.c:37自行extern)。
调用的外部函数/变量
Flash_Read/Flash_Write/Flash_Erase_Sector/Flash_Erase_Block(hardware/flash/flash.h)、FLASH_ADDR_TO_SECTOR/_TO_BLOCK/_BLOCK_TO_ADDR、FLASH_SECTOR_SIZE、FLASH_BLOCK_SIZEGetCrcCode_Modbus(common/crc.h)g_t_ems_info、SYSTEM_DATETIME(data/data.h)g_t_bat_info(midware/bms/bms.h)、g_t_inv_info(midware/inverter/inverter.h)、g_t_evc_run_info(evc.h)、g_t_evc_ii_run_info(evc_ii.h)、g_t_meter(meter.h)g_stEMSInfo(net/ems.h/server.h,用于bIsLogin、bIsBuiltSocket)get_system_sn(data/system_config)IsDownloadEMS(net/ems_download.h)OSTimeGet(uCOS-II)error_log、fill_history_error_log_data、get_lcd_history_error_log_data、g_u32_query_lcd_history_error_log_data_tick(hmi/ui/ui.h)LED_BUTTON(hmi/key.h)、g_t_ui_login(hmi/ui/ui.h)、IWDG_Feed(hardware)
6. 依赖关系
依赖
fault_warn_log.h(自身头)、<time.h>、system_aux.h、ems_download.h、crc.h、ems.h、system_config.h、gpio.h、ui.h、iwdg.h、key.h;通过头文件间接依赖 chip.h、pcf8563.h、sdram.h、flash.h、data.h、bms.h、evc.h、evc_ii.h、inverter.h、meter.h。
被依赖
data/data.c(初始化、周期处理、工厂复位)net/ems.c(get_show_errcode、读取g_t_error_log_tab.u8_error_log_send_flag/u32_error_log_send_len/u8_error_log_buff打包STATUS_SEND_ERROR_LOG)net/server.c(发送成功回执set_error_log_data_send_ok_true)hmi/led.c、hmi/ui/ui_main.c、hmi/ui/ui_history_error_log.chardware/flash/feeprom.c、data/system_config/system_config.c、data/data.c、midware/bms/bms.c、midware/inverter/set/set_comm_can.c
7. 备注与风险点
release_errcode存在数组越界读(fault_warn_log.c:1817-1829):循环体先执行s_t_errcode.u32_errcode_buf[i] = s_t_errcode.u32_errcode_buf[i + l_u8_offset];再判断i + l_u8_offset >= u8_errcode_Write才break。当u8_errcode_Write == ERRCODE_FIFO_SIZE(10)且最后一项命中删除时,会读出u32_errcode_buf[10](数组只有 10 个元素),属越界读。- 差分扫描会漏事件:镜像在每轮末尾被整体覆盖,若某故障位在 500ms 窗口内"置位—清零"自恢复,则永久不会产生日志;反之若轮询被长任务挤占,也会漏记中间态。
- 差分表不完整即丢失变化:
u32_all的比较只是"快速跳过"的门闩,但真正逐位扫的只有表中列出的FAULT_CODE_PAIR_T。若实时位域中某位置位而表中没有对应项,则该位变化永远不会被记录(例如 EMS 表里没有 E0018~E0030 等区段)。 - 硬编码簇数:BMS 保护/告警循环用
13、package_display_error_code里 BMS 显示位只 OR 了u_bms_fault_log[0..6]、EVC-II 只 OR 了[0..3],与BATTERY_MAX_NUM(12)+1、MAX_EVC_II_NUM(4)虽然当前一致,但都不是用宏表达,扩簇时极易漏改。 error_log_data_addr_save复用同一个l_u8_res:三段重试共用同一变量,且该变量初值FALSE(0) 与FLASH_ERR(0) 同值;虽然三段各自先赋值再判断、逻辑上不影响结果,但函数返回值l_u8_res未被使用,调用方无法感知地址保存是否成功。- 发送指针推进公式的 off-by-one 嫌疑(
fault_warn_log.c:381/396):(FLASH_ADDR_TO_SECTOR(save_addr) + 1) * FLASH_SECTOR_SIZE得到的是"保存地址所在扇区的下一个扇区首地址";当save_addr恰好落在扇区首地址时,会跳过整整一个扇区(4096B)未读日志,造成日志丢失。 get_show_errcode不做边界检查(fault_warn_log.c:1877):仅判断 FIFO 是否为空,直接用调用方传入的offset索引u32_errcode_buf[10]。hmi/ui/ui_main.c与net/ems.c:850必须自行用lcd_get_errcode_buf_len()约束 offset,否则越界读。read_bat_heat_fault_flag在头文件中重复声明:fault_warn_log.h:727声明void set_bat_heat_fault_flag(...),fault_warn_log.h:728前一行缺少换行分隔,紧接着写extern u8 read_bat_heat_fault_flag(void);——extern在函数声明上虽是合法的,但风格与同文件其它声明不一致。erase_error_log的整块计数可疑(fault_warn_log.c:1641):FLASH_ADDR_TO_BLOCK(l_u32_end_block_addr - l_u32_start_block_addr)是对"两地址之差"取整,而末尾零头扇区又以l_u32_end_block_addr为起点重算,边界上可能少擦或多擦一个块,需实机验证。- 魔法数字:
3*60*1000(LCD 历史刷新周期)、180(无,那是 resume 模块)、50(历史查询上限)、10(FIFO 深度)、0..6、13、[0..3]等硬编码散落在函数体内。 DEBUG_FLASH_DATA_STORE宏与本目录fault_warn_log.h:30和flash_data_store.h:20中同名宏重复定义,本文件实际包含的是fault_warn_log.h的版本,容易误判调试开关生效范围。STORE_ERROR_LOG_DATA_T.s32_fault_value字段从未赋值,落盘数据恒为 0(配合u8_reserve[12]使结构凑满 32 字节,可整除 4096 的扇区大小)。