/** * @file fault_flash_impl.c * @brief 历史故障记录:EEPROM 索引 + 外部 Flash 数据区实现。 * * 迁移说明(参考 CCU601E_D): * - EEPROM(fm24cl16)仅存储 S_HIS_FAULT_MNG 索引信息,减少擦写与上电恢复成本。 * - 外部 Flash(externalflash)按扇区保存 HIS_FAULT_DATA_T 记录内容。 * - 每条记录格式:1字节 RECORD_HEADER + 数据 + 1字节CRC(低8位)。 */ #include "flash_file_mgr/fault_flash_impl.h" #include #include "publicdata/publicdata.h" #include "publicdata/public_define.h" #include "eeprom/fm24cl16.h" #include "externalflash/flash_external_data.h" /* 兼容抽象:默认使用 FreeRTOS 堆 */ #ifndef FLASH_MGR_MALLOC #define FLASH_MGR_MALLOC(sz) pvPortMalloc((sz)) #endif #ifndef FLASH_MGR_FREE #define FLASH_MGR_FREE(ptr) vPortFree((ptr)) #endif #define HIS_FAULT_MNG_HEADER (0x5AA5u) #define FAULT_MNG_EEPROM_ADDR ((U16_T)EEPROM_ADDR_HISALARM_MNG) #define FAULT_RECORD_RETRY (3u) /* 来自故障任务:全局管理索引 */ extern S_HIS_FAULT_MNG s_hisFaultMng; void v_fault_flash_init(void) { /* 上电恢复 EEPROM 中的历史故障管理索引。 */ v_read_eeprom_hisFaultMng(&s_hisFaultMng); /* 管理信息异常时回退到安全默认值。 */ if ((s_hisFaultMng.u16_head != HIS_FAULT_MNG_HEADER) || (s_hisFaultMng.u16_hisFaultCnt > HIS_FAULT_MAX_CNT) || (s_hisFaultMng.u16_currIndex > HIS_FAULT_MAX_CNT)) { v_fault_clear_his_fault(); } } static U16_T fault_sector_record_count(void) { return (U16_T)(SPI_SECTOR_SIZE / (sizeof(HIS_FAULT_DATA_T) + 2u)); } void v_write_eeprom_hisFaultMng(S_HIS_FAULT_MNG *hisFaultMng) { S_HIS_FAULT_MNG tmp; if (hisFaultMng == NULL) { return; } tmp.u16_head = HIS_FAULT_MNG_HEADER; tmp.u16_hisFaultCnt = hisFaultMng->u16_hisFaultCnt; tmp.u16_currIndex = hisFaultMng->u16_currIndex; eeprom_buffer_write((U8_T *)&tmp, FAULT_MNG_EEPROM_ADDR, (U16_T)sizeof(S_HIS_FAULT_MNG)); } void v_read_eeprom_hisFaultMng(S_HIS_FAULT_MNG *hisFaultMng) { S_HIS_FAULT_MNG tmp; U8_T i; if (hisFaultMng == NULL) { return; } memset(&tmp, 0, sizeof(tmp)); for (i = 0u; i < FAULT_RECORD_RETRY; i++) { eeprom_buffer_read((U8_T *)&tmp, FAULT_MNG_EEPROM_ADDR, (U16_T)sizeof(S_HIS_FAULT_MNG)); if ((eeprom_get_last_error() == 0u) && (tmp.u16_head == HIS_FAULT_MNG_HEADER)) { hisFaultMng->u16_head = HIS_FAULT_MNG_HEADER; hisFaultMng->u16_hisFaultCnt = tmp.u16_hisFaultCnt; hisFaultMng->u16_currIndex = tmp.u16_currIndex; return; } } /* 失败时给出安全默认值,避免野数据参与索引计算。 */ hisFaultMng->u16_head = 0u; hisFaultMng->u16_hisFaultCnt = 0u; hisFaultMng->u16_currIndex = RECORD_ZERO_SAVE; } void v_fault_clear_his_fault(void) { s_hisFaultMng.u16_head = HIS_FAULT_MNG_HEADER; s_hisFaultMng.u16_hisFaultCnt = 0u; s_hisFaultMng.u16_currIndex = RECORD_ZERO_SAVE; v_write_eeprom_hisFaultMng(&s_hisFaultMng); } U16_T u16_fault_get_his_count(void) { S_HIS_FAULT_MNG mng; memset(&mng, 0, sizeof(mng)); v_read_eeprom_hisFaultMng(&mng); if (mng.u16_head != HIS_FAULT_MNG_HEADER) { return 0u; } if (mng.u16_hisFaultCnt > HIS_FAULT_MAX_CNT) { return HIS_FAULT_MAX_CNT; } return mng.u16_hisFaultCnt; } U8_T u8_fault_read_his_by_newest(U16_T newest_pos, HIS_FAULT_DATA_T *pt_hisFault) { S_HIS_FAULT_MNG mng; U16_T total; U16_T slot; if (pt_hisFault == NULL) { return 0u; } memset(pt_hisFault, 0, sizeof(*pt_hisFault)); total = u16_fault_get_his_count(); if ((total == 0u) || (newest_pos >= total)) { return 0u; } memset(&mng, 0, sizeof(mng)); v_read_eeprom_hisFaultMng(&mng); if ((mng.u16_head != HIS_FAULT_MNG_HEADER) || (mng.u16_currIndex == RECORD_ZERO_SAVE)) { return 0u; } slot = (U16_T)((mng.u16_currIndex + HIS_FAULT_MAX_CNT - newest_pos) % HIS_FAULT_MAX_CNT); v_read_hisFault_record(pt_hisFault, slot); return (pt_hisFault->e_fault_info == E_FAULT_NULL) ? 0u : 1u; } void v_read_hisFault_record(HIS_FAULT_DATA_T *pt_hisFault, U16_T u16_index) { U16_T rec_size = (U16_T)sizeof(HIS_FAULT_DATA_T); U16_T one_sector_cnt = fault_sector_record_count(); U32_T addr; U16_T sector_idx; U16_T sector_rec_idx; U8_T retry; U8_T *buf; if ((pt_hisFault == NULL) || (one_sector_cnt == 0u)) { return; } buf = (U8_T *)FLASH_MGR_MALLOC((size_t)rec_size + 2u); if (buf == NULL) { return; } memset(pt_hisFault, 0, sizeof(*pt_hisFault)); for (retry = 0u; retry < FAULT_RECORD_RETRY; retry++) { sector_idx = (U16_T)(u16_index / one_sector_cnt); sector_rec_idx = (U16_T)(u16_index % one_sector_cnt); addr = (U32_T)(DATAFLASH_FAULT_ADDR + (U32_T)sector_idx * SPI_SECTOR_SIZE + (U32_T)sector_rec_idx * (rec_size + 2u)); if (s32_flash_dataflash_read(addr, buf, (U32_T)(rec_size + 2u)) != 0u) { continue; } if ((buf[0] == RECORD_HEADER) && (buf[rec_size + 1u] == (U8_T)u16_crc_checksum(buf + 1u, rec_size))) { memcpy(pt_hisFault, buf + 1u, rec_size); break; } } FLASH_MGR_FREE(buf); } static void v_write_hisFault_record(HIS_FAULT_DATA_T *pt_hisFault, U16_T u16_index) { U16_T rec_size = (U16_T)sizeof(HIS_FAULT_DATA_T); U16_T one_sector_cnt = fault_sector_record_count(); U16_T sector_idx; U16_T sector_rec_idx; U32_T sector_addr; U32_T addr; U8_T *buf; if ((pt_hisFault == NULL) || (one_sector_cnt == 0u)) { return; } buf = (U8_T *)FLASH_MGR_MALLOC((size_t)rec_size + 2u); if (buf == NULL) { return; } buf[0] = RECORD_HEADER; memcpy(buf + 1u, pt_hisFault, rec_size); buf[rec_size + 1u] = (U8_T)u16_crc_checksum((U8_T *)pt_hisFault, rec_size); sector_idx = (U16_T)(u16_index / one_sector_cnt); sector_rec_idx = (U16_T)(u16_index % one_sector_cnt); sector_addr = (U32_T)(DATAFLASH_FAULT_ADDR + (U32_T)sector_idx * SPI_SECTOR_SIZE); addr = (U32_T)(sector_addr + (U32_T)sector_rec_idx * (rec_size + 2u)); /* 扇区首条记录写入前先擦除,避免旧数据残留影响 CRC。 */ if (sector_rec_idx == 0u) { (void)s32_flash_dataflash_erase_sector(sector_addr); } (void)s32_flash_dataflash_write(addr, buf, (U32_T)(rec_size + 2u)); FLASH_MGR_FREE(buf); } void v_hisFault_save_record(HIS_FAULT_DATA_T *pt_hisFault_data) { if (pt_hisFault_data == NULL) { return; } if (s_hisFaultMng.u16_currIndex == RECORD_ZERO_SAVE) { s_hisFaultMng.u16_currIndex = 0u; } else { s_hisFaultMng.u16_currIndex = (U16_T)((s_hisFaultMng.u16_currIndex + 1u) % HIS_FAULT_MAX_CNT); } if (s_hisFaultMng.u16_hisFaultCnt < HIS_FAULT_MAX_CNT) { s_hisFaultMng.u16_hisFaultCnt++; } v_write_hisFault_record(pt_hisFault_data, s_hisFaultMng.u16_currIndex); v_write_eeprom_hisFaultMng(&s_hisFaultMng); }