Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* @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 <string.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user