2024-08-23 11:16:27 +08:00
|
|
|
|
// /*
|
|
|
|
|
// * @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"
|
2024-08-22 16:24:54 +08:00
|
|
|
|
|
2024-08-23 11:16:27 +08:00
|
|
|
|
// #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);
|
2024-08-22 16:24:54 +08:00
|
|
|
|
|