CIU32_L051_M307R/bsp/src/bsp_flash.c

708 lines
25 KiB
C
Raw Normal View History

// /*
// * @Author: mbw
// * @Date: 2024-08-22 16:15:08
// * @LastEditors: mbw && 1600520629@qq.com
// * @LastEditTime: 2024-08-23 10:17:35
// * @FilePath: \USART1_Interrupt - RT-Thread\bsp\src\bsp_flash.c
// * @Description:
// *
// * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
// */
// #include "bsp_flash.h"
// #define LOG_TAG "bsp_flash" // 该模块对应的标签。不定义时默认NO_TAG
// #define LOG_LVL LOG_LVL_DBG // 该模块对应的日志输出级别。不定义时,默认:调试级别
// #include <ulog.h> // 必须在 LOG_TAG 与 LOG_LVL 下面
// // #define TEST 512
// #define MAX(a, b) ((a) > (b)) ? (a) : (b)
// void Flash_Write_Record(TeRecord record);
// CRC_HandleTypeDef sCRCConfig = {0};
// MultiTimer MultiFlash;
// static FLASH_EraseInitTypeDef sFlashEraseInit;
// const uint32_t hr_start_addr[7] = {FLASH_HR_ALARM_START_ADDR, FLASH_HR_ALARM_RCY_START_ADDR,
// FLASH_HR_FAULT_START_ADDR, FLASH_HR_FAULT_RCY_START_ADDR,
// FLASH_HR_POWER_FAILURE_START_ADDR, FLASH_HR_POWER_ON_START_ADDR,
// FLASH_HR_SENSOR_FAILURE_START_ADDR};
// /*各历史数据的条数*/
// const uint8_t hr_record_max_num[7] = {HR_ALARM_MAX_NUM, HR_ALARM_RCY_MAX_NUM,
// HR_FAULT_MAX_NUM, HR_FAULT_RCY_MAX_NUM,
// HR_POWER_FAILURE_MAX_NUM, HR_POWER_ON_MAX_NUM,
// HR_SENSOR_FAILURE_MAX_NUM};
// const uint8_t hr_record_pages[7] = {HR_ALARM_PAGES, HR_ALARM_RCY_PAGES,
// HR_FAULT_PAGES, HR_FAULT_RCY_PAGES,
// HR_POWER_FAILURE_PAGES, HR_POWER_ON_PAGES,
// HR_SENSOR_FAILURE_PAGES};
// void Multi_Flash_Callback(MultiTimer* timer, void* userData)
// {
// static uint16_t cnt = 0;
// if (cnt > 2)
// {
// cnt = 0;
// MultiTimerStop(&MultiFlash);
// }
// else
// {
// cnt++;
// Flash_Write_Record(kRecordSensorFailure);
// MultiTimerStart(&MultiFlash, 1000*1, Multi_Flash_Callback, "1s");
// }
// }
// // 将16位数据进行类型转换
// uint16_t Type_Conversion(uint16_t data)
// {
// uint16_t value;
// // 交换数据的高低位
// value = ((data & 0xFF) << 8) | ((data >> 8) & 0xFF);
// // logDebug("value = %#x data = %#x\r\n", value, data);
// return value;
// }
// /**
// * @description: 参数模型CRC-16/X25 X16+X12+X5+1
// * @return {*}由于写入FLASH数据需要对数据进行CRC校验这里使用HAL_CRC_Calculate函数计算CRC值此时存储顺序是按照高低位反转求取到的
// * 比如2024这个十进制数在内存中存储为07E8在FLASH中存储为E807所以在计算CRC值时,按照高低位这种小端模式进行计算CRC
// */
// uint16_t BSP_Get_Crc(uint8_t *buf, size_t len)
// {
// uint16_t crc_value;
// crc_value = HAL_CRC_Calculate(&sCRCConfig, buf, len);
// logDebug("crc_value = %#x\r\n", crc_value);
// return crc_value; // 高位在前
// }
// #if 0
// uint16_t BSP_Get_Crc(TuFlashHrRecordFrame frme)
// {
// uint16_t crc_value = 0;
// uint8_t crc_buf[8] = {0};
// // 在内存中存储为小端存储故先存储低位再存储高位CRC校验时需要反转顺序
// crc_buf[0] = frme.buf[1]; // 低位
// crc_buf[1] = frme.buf[0]; // 高位
// crc_buf[2] = frme.buf[3];
// crc_buf[3] = frme.buf[2];
// crc_buf[4] = frme.buf[4];
// crc_buf[5] = frme.buf[5];
// crc_buf[6] = frme.buf[6];
// crc_buf[7] = frme.buf[7];
// logDebug("crc_buf\r\n");
// for (uint8_t i = 0; i < sizeof(crc_buf); i++)
// {
// logDebug("%02x ", crc_buf[i]);
// }
// crc_value = HAL_CRC_Calculate(&sCRCConfig, crc_buf, 8);
// logDebug("crc_value = %#x\r\n", crc_value);
// return crc_value; // 高位在前
// }
// #endif
// void BSP_Crc_Init(void)
// {
// __HAL_RCC_CRC_CLK_ENABLE();
// sCRCConfig.Instance = CRC;
// HAL_CRC_Init(&sCRCConfig);
// }
// /**
// * @description: 读取Flash地址中的数据
// * @param {uint32_t} addr
// * @param {uint8_t} *buf
// * @param {size_t} len
// * @return {*}
// */
// static size_t Flash_Read(uint32_t addr, uint8_t *buf, size_t len)
// {
// size_t read_len = 0;
// for (size_t i = 0; i < len; i++, buf++, addr++, read_len++)
// {
// *buf = *(uint8_t *)addr;
// // logDebug("buf[%d]= %d\r\n", i, *buf);
// }
// return read_len;
// }
// /**
// * @description: 向Flash中写入数据
// * @param {uint32_t} addr
// * @param {uint8_t} *buf
// * @param {size_t} len
// * @return {*}
// */
// static size_t Flash_Write(uint32_t addr, uint8_t *buf, size_t len)
// {
// size_t i = 0;
// for (i = 0; i < len; i++, buf++, addr++)
// {
// // logDebug("addr = %#X, buf[%d] = %d\r\n", addr, i, *(uint8_t *)buf);
// if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr, *(uint8_t *)buf) != HAL_OK) // 写入操作 字节写入
// {
// logDebug("addr = %#X, read %d\r\n", addr, *(uint8_t *)addr);
// }
// if (*(uint8_t *)addr != *(uint8_t *)buf)
// {
// logDebug("Flash_Write Data Mismatch at addr %#X, expected %d got %d\r\n", addr, *(uint8_t *)buf, *(uint8_t *)addr);
// break; // 中断循环,因为数据不匹配
// }
// }
// return i;
// }
// /**
// * @description: 擦除产品信息页
// * @return {*}
// */
// void Flash_ErasePage_ConfigInfo(void)
// {
// static uint32_t error_page;
// sFlashEraseInit.TypeErase = FLASH_TYPEERASE_PAGES; // 页擦除
// sFlashEraseInit.PageAddress = FLASH_CONFIG_INFO_START_ADDR; // 开始擦除地址 必须以512Byte为单位
// sFlashEraseInit.NbPages = 1;
// if (HAL_FLASH_Erase(&sFlashEraseInit, &error_page) != HAL_OK)
// {
// logDebug("error_page = %#x\r\n", error_page);
// Error_Handler();
// }
// }
// /**
// * @description: 写产品信息页(最后一页)
// * @param {uint8_t*} frame
// * @return {*}
// */
// void Flash_Write_ConfigInfo(uint8_t *frame)
// {
// Flash_Write(FLASH_CONFIG_INFO_START_ADDR, frame, FLASH_PAGE_SIZE);
// }
// /**
// * @description: 擦除历史记录区的页
// * @param {TeRecord} record 需要擦除的项目
// * @param {uint8_t} page_offset 需要擦除的页偏移量
// * @return {*}
// */
// static ErrorStatus Flash_ErasePage_Records(TeRecord record, uint8_t page_offset)
// {
// ErrorStatus flag = SUCCESS;
// static uint32_t error_page;
// uint8_t erase_page = 0;
// if (page_offset <= hr_record_pages[record] - 1)
// {
// erase_page = page_offset;
// }
// else
// {
// erase_page = hr_record_pages[record] - 1;
// }
// sFlashEraseInit.TypeErase = FLASH_TYPEERASE_PAGES; // 页擦除
// sFlashEraseInit.PageAddress = hr_start_addr[record] + FLASH_PAGE_SIZE * erase_page; // 开始擦除地址 必须以512Byte为单位
// sFlashEraseInit.NbPages = 1;
// if (HAL_FLASH_Erase(&sFlashEraseInit, &error_page) != HAL_OK)
// {
// Error_Handler();
// }
// for (uint16_t i = 0; i < FLASH_PAGE_SIZE; i++) // 检查擦除是否完整
// {
// if (FLASH_Byte_Read((hr_start_addr[record] + FLASH_PAGE_SIZE * erase_page) + i) != 0xFF)
// {
// flag = ERROR;
// }
// }
// // logDebug("/**Flash_Erase(%d)Page(%d)=%d**/\r\n", record, erase_page, flag);
// return flag;
// }
// /**
// * @description: 擦除数据记录区
// * @return {*}
// */
// void BSP_Flash_EraseRecodrs(void)
// {
// /*擦除所有的历史记录区*/
// for (TeRecord record = kRecordAlarm; record < kRecordSensorFailure; record++)
// {
// for (uint8_t i = 0; i < hr_record_pages[record]; i++)
// {
// Flash_ErasePage_Records(record, i);
// }
// }
// /*擦除初始信息区*/
// Flash_ErasePage_ConfigInfo();
// }
// /**
// * @description: 先读再擦,以确保原有数据不会被擦除
// * @param {uint8_t} *page_buf
// * @return {*}
// */
// void Flash_ErasePage_ReadConfigInfo(uint8_t *page_buf)
// {
// Flash_Read(FLASH_CONFIG_INFO_START_ADDR, page_buf, FLASH_PAGE_SIZE);
// Flash_ErasePage_ConfigInfo();
// }
// /**
// * @description: 获取产品的出厂或到期时间
// * @return {*}
// */
// ErrorStatus Flash_GetProductTimeLimit(TuFlashProductTimeLimitFrame *pLimitTime, TeFlashProductTimeLimitId id)
// {
// ErrorStatus flag = ERROR;
// uint32_t addr = 0;
// if (id == kFactoryTimeId)
// {
// addr = FLASH_FACTORY_TIME_START_ADDR;
// }
// else if (id == kExpirationTimeId)
// {
// addr = FLASH_EXPIRATION_TIME_START_ADDR;
// }
// if (addr != 0)
// {
// Flash_Read(addr, pLimitTime->buf, sizeof(TuFlashProductTimeLimitFrame));
// // logDebug("pLimitTime->Struct.header = %#x\r\n", pLimitTime->Struct.header);
// if (pLimitTime->Struct.header == FLASH_PRODUCT_TIME_FRAME_HEADER)
// {
// flag = SUCCESS;
// logDebug("Flash_GetProductTimeLimit(%d):%04d-%02d-%02d,%02d:%02d:%02d\r\n", id,
// pLimitTime->Struct.year, pLimitTime->Struct.month, pLimitTime->Struct.day,
// pLimitTime->Struct.hour, pLimitTime->Struct.minute, pLimitTime->Struct.second);
// }
// else
// {
// logDebug("Flash_GetProductTimeLimit Error!");
// }
// }
// return flag;
// }
// /**
// * @description: 设置产品的出厂或到期时间
// * @param {uint16_t} year
// * @param {uint8_t} mon
// * @param {uint8_t} day
// * @param {uint8_t} hour
// * @param {uint8_t} min
// * @param {uint8_t} second
// * @param {TeFlashProductTimeLimitId} id
// * @return {*}
// */
// void Flash_SetProductTimeLimit(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t second, TeFlashProductTimeLimitId id)
// {
// TuFlashProductTimeLimitFrame LimitTime;
// TuFlashProductTimeLimitFrame ReadLimitTime;
// uint8_t in_page_offset = 0;
// uint8_t page_buf[FLASH_PAGE_SIZE] = {0}; // 暂存最后一页的值
// Flash_ErasePage_ReadConfigInfo(page_buf);
// LimitTime.Struct.header = FLASH_PRODUCT_TIME_FRAME_HEADER;
// LimitTime.Struct.year = year;
// LimitTime.Struct.month = mon;
// LimitTime.Struct.day = day;
// LimitTime.Struct.hour = hour;
// LimitTime.Struct.minute = min;
// LimitTime.Struct.second = second;
// if (id == kFactoryTimeId)
// {
// in_page_offset = (FLASH_FACTORY_TIME_START_ADDR - FLASH_CONFIG_INFO_START_ADDR);
// }
// else if (id == kExpirationTimeId)
// {
// in_page_offset = (FLASH_EXPIRATION_TIME_START_ADDR - FLASH_CONFIG_INFO_START_ADDR);
// }
// for (uint8_t i = 0; i < sizeof(TuFlashProductTimeLimitFrame); i++)
// {
// page_buf[in_page_offset + i] = LimitTime.buf[i];
// }
// Flash_Write_ConfigInfo(&page_buf[0]);
// Flash_GetProductTimeLimit(&ReadLimitTime, id);
// }
// /**
// * @description: 产品信息初始化,
// * @return {*}
// */
// void BSP_Flash_Init(void)
// {
// BSP_Crc_Init();
// if (*(uint16_t *)FLASH_INIT_FLAG_ADDR != FLASH_FIRST_INIT_VALUE)
// {
// uint8_t flash_init_flag[2];
// flash_init_flag[0] = FLASH_FIRST_INIT_VALUE % 256; // 256
// flash_init_flag[1] = FLASH_FIRST_INIT_VALUE / 256; // 0
// BSP_Flash_EraseRecodrs(); // 擦除历史数据区
// Flash_Write(FLASH_INIT_FLAG_ADDR, flash_init_flag, sizeof(flash_init_flag));
// Flash_SetProductTimeLimit(2023, 3, 22, 13, 58, 20, kFactoryTimeId); // 出厂时间
// Flash_SetProductTimeLimit(2028, 3, 22, 13, 58, 20, kExpirationTimeId); // 到期时间
// }
// }
// /**
// * @description: 获取最大的已经记录的项目数,此处的数目是包含缓冲页
// * @param {TeRecord} record
// * @return {*}
// */
// static uint16_t Flash_GetMaxIndex_Records(TeRecord record)
// {
// uint16_t index_max = 0;
// for (uint8_t page = 0; page < hr_record_pages[record]; page++) // 遍历对应项的历史数据扇区
// {
// for (uint8_t i = 0; i <= FLASH_PAGE_HR_RECORD_NUM; i++) // 获取扇区偏移量
// {
// // 当无记录时会有0xFFFF极端情况出现最大记录数是65536 不过要想出现这个数相当于一天报警59次连续报警三年已经达到设备使用年限了所以不考虑这种情况
// if (*(uint16_t *)(hr_start_addr[record] + FLASH_PAGE_SIZE * page + FLASH_HR_ONE_RECORD_SIZE * i) != 0xFFFF)
// {
// index_max = MAX(index_max, *(uint16_t *)(hr_start_addr[record] + FLASH_PAGE_SIZE * page + FLASH_HR_ONE_RECORD_SIZE * i));
// }
// else
// {
// break; // 遇到0xFFFF说明已经没有记录了退出循环
// }
// }
// }
// return index_max;
// }
// /**
// * @description: 最大只能获取到的值不包含缓冲区的那一页值数目
// * @param {TeRecord} record
// * @return {*}
// */
// uint8_t Flash_GetNum_Records(TeRecord record)
// {
// uint8_t num = 0;
// uint16_t num_max = Flash_GetMaxIndex_Records(record);
// if (num_max <= hr_record_max_num[record])
// {
// num = num_max;
// }
// else
// {
// num = hr_record_max_num[record];
// }
// return num;
// }
// /**
// * @description: 此处的index_max是该项目的最大存储数而不是历史数据最大存储数
// * 比如报警记录是4+1页共5*51 = 255条index_max = 255条
// * 而 hr_record_max_num[record]是我们历史数据最大存储数是4*56=204条
// * @param {TuFlashHrRecordFrame} *pHrRecord
// * @param {TeRecord} record
// * @param {uint8_t} index
// * @return {*}
// */
// void Flash_Read_Record(TuFlashHrRecordFrame *pHrRecord, TeRecord record, uint8_t index)
// {
// uint16_t index_max = Flash_GetMaxIndex_Records(record); // 真实可最大存储量,
// logDebug("\r\nindex_max = %d\r\n", index_max);
// uint8_t page_offset = 0; // 扇区偏移
// uint8_t in_page_offset = 0; // 扇区内偏移
// uint16_t crc_value;
// if (index <= index_max) // 要索引的值必须小于这个最大索引值,否则会出现数据越界
// {
// /*数据存储中报警信息204条当索引大于204时说明前4页已经写满开始写第五页
// 此时最近的204条数据的起始地址发生变化需要重定向起始地址*/
// if (index_max > hr_record_max_num[record]) // 当大于最大的历史数据比如204
// {
// if (record < kRecordSensorFailure)
// {
// /*比如207条时最新的204条数据是从第三207-204条开始的此时要检索比如第10条数据则应该是207-204+10*/
// uint16_t index_redirect = index_max - hr_record_max_num[record] + index;
// logDebug("index_redirect = %d\r\n", index_redirect);
// /*获取其所在扇区地址*/
// page_offset = ((index_redirect - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
// /*获取其所在扇区偏移量*/
// in_page_offset = ((index_redirect - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
// }
// else
// {
// page_offset = 0;
// in_page_offset = ((index_max - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
// }
// }
// else // 如果未写到缓存区页,则历史数据的起始地址不变
// {
// page_offset = ((index - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
// in_page_offset = ((index - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
// }
// logDebug("page_offset = %d\r\n", page_offset);
// logDebug("in_page_offset = %d\r\n", in_page_offset);
// uint32_t addr = (hr_start_addr[record] + FLASH_PAGE_SIZE * page_offset + in_page_offset);
// logDebug("addr = %04X\r\n", addr);
// crc_value = HAL_CRC_Calculate(&sCRCConfig, (uint8_t *)(addr), 8);
// logDebug("crc_value = %X\r\n", crc_value);
// if (crc_value == *(uint16_t *)(addr + 8))
// {
// Flash_Read(addr, pHrRecord->buf, HR_RECORD_FRAME_LEN);
// logDebug("Flash_Read_(%d)Record(%d):%04d-%02d-%02d,%02d:%02d\r\n", record, index,
// pHrRecord->Struct.year, pHrRecord->Struct.month, pHrRecord->Struct.day,
// pHrRecord->Struct.hour, pHrRecord->Struct.minute);
// }
// else
// {
// memset(pHrRecord->buf, 0, HR_RECORD_FRAME_LEN);
// logDebug("Flash_GetMaxNum_(%d)Records Error!: (index_max)%d < %d", record, index_max, index);
// }
// }
// else
// {
// memset(pHrRecord->buf, 0, HR_RECORD_FRAME_LEN);
// logDebug("Flash_GetMaxNum_(%d)Records Error!: (index_max)%d < %d", record, index_max, index);
// }
// }
// /**
// * @description: 写入一次历史数据信息
// * @param {TuFlashHrRecordFrame} *pHrRecord
// * @param {TeRecord} record
// * @param {uint16_t} index
// * @return {*}
// */
// void Flash_Write_RecordIndex(TuFlashHrRecordFrame *pHrRecord, TeRecord record, uint16_t index)
// {
// // logDebug("/*********Flash_Write_RecordIndex***************/");
// uint8_t page_offset = ((index - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
// logDebug("page_offset = %d\r\n", page_offset);
// uint16_t in_page_offset = ((index - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
// logDebug("in_page_offset = %d\r\n", in_page_offset);
// uint32_t addr = (hr_start_addr[record] + FLASH_PAGE_SIZE * page_offset + in_page_offset);
// logDebug("addr = %04X\r\n", addr);
// Flash_Write(addr, pHrRecord->buf, HR_RECORD_FRAME_LEN);
// TuFlashHrRecordFrame pReadRecord;
// Flash_Read(addr, pReadRecord.buf, HR_RECORD_FRAME_LEN);
// logDebug("(%04X)Flash_Write_(%d)RecordIndex(%d):%04d-%02d-%02d,%02d:%02d\r\n",
// pReadRecord.Struct.crc16, record, pReadRecord.Struct.index,
// pReadRecord.Struct.year, pReadRecord.Struct.month, pReadRecord.Struct.day,
// pReadRecord.Struct.hour, pReadRecord.Struct.minute);
// }
// /**
// * @description: 向对应的历史数据存储区写入一次数据
// * @param {TeRecord} record
// * @return {*}
// */
// void Flash_Write_Record(TeRecord record)
// {
// // logDebug("/*********Flash_Write_Record***************/\r\n");
// uint16_t index_max = Flash_GetMaxIndex_Records(record);
// uint16_t index_new = index_max + 1;
// logDebug("index_new = %d\r\n", index_new);
// uint16_t index_start;
// uint8_t index_start_page_offset;
// uint8_t index_max_page_offset;
// uint8_t index_max_in_page_offset;
// if (index_max <= hr_record_max_num[record]) // 如果小于等于历史记录数,则起始地址不变
// {
// index_start = 0;
// index_start_page_offset = 0;
// index_max_page_offset = ((index_max - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record]; // 最近一次写入值的页偏移量
// logDebug("index_max_page_offset = %d\r\n", index_max_page_offset);
// }
// else // 大于历史数据记录数,在缓存区
// {
// index_start = index_max - (hr_record_max_num[record] - 1); // 开始索引地址
// // logDebug("index_start = %d\r\n", index_start);
// index_start_page_offset = ((index_start - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record]; // 看起始地址偏移量
// // logDebug("index_start_page_offset = %d\r\n", index_start_page_offset);
// index_max_page_offset = ((index_max - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
// }
// index_max_in_page_offset = (index_max - 1) % FLASH_PAGE_HR_RECORD_NUM; // 在页内的偏移量
// // logDebug("index_max_in_page_offset = %d\r\n", index_max_in_page_offset);
// /*当写入数据已经是缓存区的最后一组数据时,将第一页擦除,方便下次写入*/
// if ((index_max_in_page_offset + 1) == (FLASH_PAGE_HR_RECORD_NUM - 1) && index_max_page_offset == (hr_record_pages[record] - 1))
// {
// Flash_ErasePage_Records(record, 0);
// }
// /*当开始第N次循环写入时当写到当前页最后一个字节时删除项目的下一页*/
// else if ((index_max_in_page_offset + 1) == (FLASH_PAGE_HR_RECORD_NUM - 1) && index_max_page_offset == index_start_page_offset - 1)
// {
// Flash_ErasePage_Records(record, index_max_page_offset + 1);
// }
// BSP_Get_RTC_Time();
// TuFlashHrRecordFrame HrRecord;
// HrRecord.Struct.index = index_new;
// HrRecord.Struct.year = RtcDate.Year;
// HrRecord.Struct.month = RtcDate.Month;
// HrRecord.Struct.day = RtcDate.Date;
// HrRecord.Struct.hour = RtcTime.Hours;
// HrRecord.Struct.minute = RtcTime.Minutes;
// HrRecord.Struct.crc16 = BSP_Get_Crc(HrRecord.buf, HR_RECORD_FRAME_LEN - 2);
// // logDebug("%04d-%02d-%02d,%02d:%02d\r\n", HrRecord.Struct.year, HrRecord.Struct.month,
// // HrRecord.Struct.day, HrRecord.Struct.hour, HrRecord.Struct.minute);
// // logDebug("HrRecord.Struct.crc16 = %04X\r\n", HrRecord.Struct.crc16);
// Flash_Write_RecordIndex(&HrRecord, record, index_new);
// }
// /**
// * @description: 获取MQ报警值
// * @return {*}
// */
// uint16_t Flash_GetMQ_AlarmValue(void)
// {
// uint16_t value = 0;
// TuFlashMqAlarmFrame MqCall;
// Flash_Read(FLASH_MQ_ALARM_VALUE_ADDR, MqCall.buf, sizeof(TuFlashMqAlarmFrame));
// if (MqCall.Struct.header == FLASH_CONFIG_INFO_FRAME_HEADER)
// {
// value = MqCall.Struct.value;
// logDebug("Flash_GetMQ_AlarmValue: %d", value);
// }
// else
// {
// logDebug("Flash_GetMQ_AlarmValue Error!");
// }
// return value;
// }
// /**
// * @description: 设置MQ报警值
// * @param {uint16_t} value
// * @return {*}
// */
// void Flash_SetMQ_AlarmValue(uint16_t value)
// {
// TuFlashMqAlarmFrame MqCal;
// uint8_t page_buf[FLASH_PAGE_SIZE];
// Flash_ErasePage_ReadConfigInfo(page_buf);
// MqCal.Struct.header = FLASH_CONFIG_INFO_FRAME_HEADER;
// MqCal.Struct.value = value;
// uint8_t in_page_offset = (FLASH_MQ_ALARM_VALUE_ADDR - FLASH_CONFIG_INFO_START_ADDR);
// for (uint8_t i = 0; i < sizeof(TuFlashMqAlarmFrame); i++)
// {
// page_buf[in_page_offset + i] = MqCal.buf[i];
// }
// Flash_Write_ConfigInfo(page_buf);
// logDebug("Flash_GetMQ_AlarmValue() = %d\r\n", Flash_GetMQ_AlarmValue());
// }
// /**
// * @description: 获取总记录数
// * @param {TsTotalRecords} *pTotalRecords
// * @return {*}
// * @note:
// */
// ErrorStatus Flash_GetTotalRecord(TsTotalRecords *pTotalRecords)
// {
// ErrorStatus flag = ERROR;
// pTotalRecords->alarm = Flash_GetNum_Records(kRecordAlarm);
// pTotalRecords->alarm_rcy = Flash_GetNum_Records(kRecordAlarmRcy);
// pTotalRecords->fault = Flash_GetNum_Records(kRecordFault);
// pTotalRecords->fault_rcy = Flash_GetNum_Records(kRecordFaultRcy);
// pTotalRecords->power_failure = Flash_GetNum_Records(kRecordPowerFailure);
// pTotalRecords->power_on = Flash_GetNum_Records(kRecordPowerOn);
// pTotalRecords->sensor_failure = Flash_GetNum_Records(kRecordSensorFailure);
// flag = SUCCESS;
// return flag;
// }
// /**
// * @brief 获取记录时间
// * @param record_type
// * @param index
// * @param pRecordsTime
// * @return ErrorStatus
// */
// ErrorStatus Flash_GetRecord(TeFrameC2 record_type, uint8_t index, TsRecordsTime *pRecordsTime)
// {
// ErrorStatus flag = ERROR;
// if (kNumOfRecords < record_type && record_type < kGetCurrentTime)
// {
// TuFlashHrRecordFrame pHrReadRecord;
// Flash_Read_Record(&pHrReadRecord, (TeRecord)(record_type - 1), index);
// logDebug("(%d)Flash_GetRecord(%d):%04d-%02d-%02d,%02d:%02d",
// record_type - 1, pHrReadRecord.Struct.index,
// pHrReadRecord.Struct.year, pHrReadRecord.Struct.month, pHrReadRecord.Struct.day,
// pHrReadRecord.Struct.hour, pHrReadRecord.Struct.minute);
// pRecordsTime->year_h = pHrReadRecord.Struct.year / 256;
// pRecordsTime->year_l = pHrReadRecord.Struct.year % 256;
// pRecordsTime->month = pHrReadRecord.Struct.month;
// pRecordsTime->day = pHrReadRecord.Struct.day;
// pRecordsTime->hour = pHrReadRecord.Struct.hour;
// pRecordsTime->minute = pHrReadRecord.Struct.minute;
// flag = SUCCESS;
// }
// return flag;
// }
// void BSP_Flash_Test(void)
// {
// // Flash_SetMQ_AlarmValue(3100);
// MultiTimerStart(&MultiFlash, 1000, Multi_Flash_Callback, "2min");
// }
// module_init("flash", BSP_Flash_Init);