972 lines
33 KiB
C
972 lines
33 KiB
C
/*
|
||
* @Author: mbw
|
||
* @Date: 2024-08-22 16:15:08
|
||
* @LastEditors: mbw && 1600520629@qq.com
|
||
* @LastEditTime: 2024-09-04 14:57:22
|
||
* @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"
|
||
#include "bsp_rtc.h"
|
||
#include "rthw.h"
|
||
#include "stdlib.h"
|
||
#include "user_rtt.h"
|
||
#include "perf_counter.h"
|
||
|
||
#define LOG_TAG "bsp_flash" // 该模块对应的标签。不定义时,默认:NO_TAG
|
||
#define LOG_LVL LOG_LVL_DBG // 该模块对应的日志输出级别。不定义时,默认:调试级别
|
||
#include <ulog.h> // 必须在 LOG_TAG 与 LOG_LVL 下面
|
||
|
||
#define FSTPG_WORD_COUNT (0x40U)
|
||
|
||
// #define TEST 512
|
||
#define MAX(a, b) ((a) > (b)) ? (a) : (b)
|
||
|
||
ErrorStatus Flash_Write_Record(TeRecord record);
|
||
|
||
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 uint16_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};
|
||
|
||
/*定义历史数据所在的真实起始页*/
|
||
const uint8_t hr_record_start_page_num[7] = {FLASH_HR_ALARM_PAGE, FLASH_HR_ALARM_RCY_PAGE,
|
||
FLASH_HR_FAULT_PAGE, FLASH_HR_FAULT_RCY_PAGE,
|
||
FLASH_HR_POWER_FAILURE_PAGE, FLASH_HR_POWER_ON_PAGE,
|
||
FLASH_HR_SENSOR_FAILIRE_START_PAGE};
|
||
|
||
/*定义信息页的数据地址*/
|
||
const uint32_t hr_record_info_start_addr[9] = {
|
||
FLASH_CONFIG_INFO_INIT_FLAG_ADDR,
|
||
FLASH_FACTORY_TIME_ADDR,
|
||
FLASH_EXPIRATION_TIME_ADDR,
|
||
FLASH_LOW_ALARM_VALUE_ADDR,
|
||
FLASH_HIGH_ALARM_VALUE_ADDR,
|
||
FLASH_SOFTWARE_VERSION_ADDR,
|
||
FLASH_HARDWARE_VERSION_ADDR,
|
||
FLASH_COMPANY_NAME_ADDR,
|
||
FLASH_UPDATE_TIME_ADDR,
|
||
};
|
||
|
||
rt_ubase_t level = 0;
|
||
static void BSP_Flash_UnLock(void)
|
||
{
|
||
std_flash_unlock();
|
||
}
|
||
|
||
static void BSP_Flash_Lock(void)
|
||
{
|
||
std_flash_lock();
|
||
// rt_hw_interrupt_enable(interrupt_value);
|
||
}
|
||
|
||
static void Flash_Interrupt_Disable(void)
|
||
{
|
||
level = rt_hw_interrupt_disable();
|
||
}
|
||
|
||
static void Flash_Interrupt_Enable(void)
|
||
{
|
||
rt_hw_interrupt_enable(level);
|
||
}
|
||
|
||
// 计算校验和的函数
|
||
uint8_t Sum_Check(TuFlashHrRecordFrame frame)
|
||
{
|
||
return (frame.time.year + frame.time.month + frame.time.day + frame.time.hour + frame.time.minute) & CHECKSUM_MASK;
|
||
}
|
||
|
||
#if 0
|
||
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;
|
||
}
|
||
|
||
return read_len;
|
||
}
|
||
#endif
|
||
static size_t Flash_ReadWord(uint32_t addr, uint32_t *buf, size_t len)
|
||
{
|
||
size_t read_len = 0;
|
||
|
||
if ((addr & 0x03) != 0) // 地址4字节对齐
|
||
{
|
||
RTT_LOG_E("addr %#X is not aligned\r\n", addr);
|
||
return ERROR;
|
||
}
|
||
for (size_t i = 0; i < len; i++, read_len++)
|
||
{
|
||
buf[i] = ((uint32_t *)addr)[i]; //
|
||
if (buf[i] != ((uint32_t *)addr)[i])
|
||
{
|
||
RTT_LOG_E("Flash_Read Data Mismatch at addr %#X, expected %d got %d", addr, *(uint32_t *)buf, *(uint32_t *)addr);
|
||
return ERROR;
|
||
}
|
||
}
|
||
return read_len;
|
||
}
|
||
/**
|
||
* @description: 向Flash中写入数据
|
||
* @param {uint32_t} addr
|
||
* @param {uint8_t} *buf
|
||
* @param {size_t} len
|
||
* @return {*}
|
||
*/
|
||
static std_status_t Flash_WriteWord(uint32_t addr, uint32_t write_data)
|
||
{
|
||
if ((addr & 0x03) != 0) // 地址4字节对齐
|
||
{
|
||
LOG_E("addr %#X is not aligned\r\n", addr);
|
||
return ERROR;
|
||
}
|
||
/* 清除错误标志 */
|
||
std_flash_clear_flag(FLASH_FLAG_ALL_ERR);
|
||
BSP_Flash_UnLock();
|
||
if (std_flash_get_lock_status() == false)
|
||
{
|
||
/* 进入编程模式 */
|
||
// std_flash_program_enable();
|
||
Flash_Interrupt_Disable();
|
||
if (std_flash_word_program(addr, write_data) != SUCCESS) // 写入操作 字节写入
|
||
{
|
||
Flash_Interrupt_Enable();
|
||
LOG_D("addr = %#X, read %d", addr, *(uint32_t *)addr);
|
||
|
||
// std_flash_program_disable();
|
||
BSP_Flash_Lock();
|
||
return ERROR;
|
||
}
|
||
Flash_Interrupt_Enable();
|
||
// std_flash_program_disable();
|
||
BSP_Flash_Lock();
|
||
if (*(uint32_t *)addr != write_data)
|
||
{
|
||
LOG_D("Flash_Write Data Mismatch at addr %#X, expected %d got %d", addr, write_data, *(uint32_t *)addr);
|
||
/* 退出编程模式 */
|
||
|
||
return ERROR;
|
||
}
|
||
rt_thread_mdelay(2);
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
#if 0
|
||
#if defined(__CC_ARM)
|
||
#pragma arm section code = "FAST_PROGRAM"
|
||
#elif defined(__ICCARM__)
|
||
__ramfunc
|
||
#elif defined(__GNUC__)
|
||
__attribute__ ((section (".RamFunc")))
|
||
#endif
|
||
|
||
/**
|
||
* @brief Flash快速编程,往目标地址快速编程半页数据
|
||
* @param address 编程地址
|
||
* @param data_buf 编程数据
|
||
* @retval std_status_t 本函数执行结果
|
||
*/
|
||
std_status_t BSP_Flash_Fast_Write(uint32_t address, uint32_t *data_buf)
|
||
{
|
||
std_status_t status = STD_OK;
|
||
uint32_t prog_count = 0;
|
||
|
||
/* 启动快速编程模式 */
|
||
std_flash_fast_program_enable();
|
||
/* 向目标地址写入数据 */
|
||
for (prog_count=0; prog_count < FSTPG_WORD_COUNT; prog_count++)
|
||
{
|
||
((uint32_t *)address)[prog_count] = data_buf[prog_count];
|
||
/* 查询等待BSY标志被清除 */
|
||
while ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY);
|
||
|
||
/* 若出现错误,则退出编程循环 */
|
||
if (FLASH->SR & FLASH_FLAG_ALL_ERR)
|
||
{
|
||
RTT_LOG_E("FLASH_SR = %#X", FLASH->SR);
|
||
RTT_LOG_E("Flash_Write Error at addr %#X, expected %X got %X", address, data_buf[prog_count], ((uint32_t *)address)[prog_count]);
|
||
status = STD_ERR;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* 查询等待FSTPG_MODE状态被自动清零 */
|
||
while ((FLASH->CR & FLASH_CR_FSTPG_MODE) == FLASH_CR_FSTPG_MODE);
|
||
|
||
/* 清除Flash标志 */
|
||
FLASH->SR = (FLASH_FLAG_ALL_ERR | FLASH_SR_EOP);
|
||
|
||
return (status);
|
||
}
|
||
|
||
#if defined(__CC_ARM)
|
||
#pragma arm section
|
||
#endif
|
||
/**
|
||
* @brief Flash快速编程流程
|
||
* @param address 编程地址
|
||
* @param data_buf 编程数据
|
||
* @retval std_status_t 本函数执行结果
|
||
*/
|
||
ErrorStatus BSP_Flash_Fast_Program(uint32_t address, uint32_t *data_buf)
|
||
{
|
||
std_status_t status = STD_OK;
|
||
uint32_t prog_count;
|
||
|
||
/* 检查Flash上一次操作忙状态、错误状态 */
|
||
// status = std_flash_wait_for_last_operation(FLASH_WAIT_PROGRAM);
|
||
// if(status == STD_OK)
|
||
// {
|
||
/* 进入编程模式 */
|
||
std_flash_program_enable();
|
||
/* 短时间屏蔽中断 */
|
||
Flash_Interrupt_Disable();
|
||
/* 执行快速编程 */
|
||
if(BSP_Flash_Fast_Write(address, data_buf) != STD_OK)
|
||
{
|
||
status = STD_ERR;
|
||
RTT_LOG_E("Flash_Fast_Write status ERROR %d", status);
|
||
}
|
||
/* 恢复中断 */
|
||
Flash_Interrupt_Enable();
|
||
|
||
/* 退出编程模式 */
|
||
std_flash_program_disable();
|
||
rt_thread_mdelay(2);
|
||
/* 快速编程中无法对Flash执行读操作,需在编程结束后统一校验数据 */
|
||
if (status == STD_OK)
|
||
{
|
||
for (prog_count = 0; prog_count < FSTPG_WORD_COUNT; prog_count++)
|
||
{
|
||
if (((__IO uint32_t *)address)[prog_count] != data_buf[prog_count])
|
||
{
|
||
RTT_LOG_E("Flash_Fast_Write Data Mismatch at addr %#X, expected %d got %d", address + prog_count * 4, data_buf[prog_count], ((__IO uint32_t *)address)[prog_count]);
|
||
status = STD_ERR;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
RTT_LOG_D("Flash_Fast_Write Data Match at addr %#X, expected %d got %d", address + prog_count * 4, data_buf[prog_count], ((__IO uint32_t *)address)[prog_count]);
|
||
}
|
||
}
|
||
}
|
||
// }
|
||
return (status);
|
||
}
|
||
|
||
|
||
ErrorStatus BSP_Flash_Program_Page(uint32_t address, uint32_t *data_buf)
|
||
{
|
||
std_status_t status;
|
||
/* 清除错误标志 */
|
||
std_flash_clear_flag(FLASH_FLAG_ALL_ERR);
|
||
|
||
/* Flash控制寄存器解锁 */
|
||
BSP_Flash_UnLock();
|
||
|
||
if (std_flash_get_lock_status() == false)
|
||
{
|
||
/* 页擦第48页 */
|
||
status = std_flash_page_erase(FLASH_HR_INFO_PAGE);
|
||
/* 擦除异常,加入自定义处理代码 */
|
||
while(status != STD_OK)
|
||
{
|
||
RTT_LOG_E("Flash_Erase Page %d", FLASH_HR_INFO_PAGE);
|
||
return STD_ERR;
|
||
}
|
||
|
||
/* 快速编程64个字:前半页 */
|
||
status = BSP_Flash_Fast_Program(address, data_buf);
|
||
/* 快速编程异常,加入自定义处理代码 */
|
||
while(status != STD_OK)
|
||
{
|
||
RTT_LOG_E("Flash_Fast_Write Page %d", FLASH_HR_INFO_PAGE);
|
||
return STD_ERR;
|
||
}
|
||
|
||
/* 快速编程64个字:后半页 */
|
||
status = BSP_Flash_Fast_Program((address + (FSTPG_WORD_COUNT << 2)), data_buf);
|
||
/* 快速编程异常,加入自定义处理代码 */
|
||
while(status != STD_OK)
|
||
{
|
||
RTT_LOG_E("Flash_Fast_Write Page %d", FLASH_HR_INFO_PAGE);
|
||
|
||
return STD_ERR;
|
||
}
|
||
/* Flash控制寄存器加锁 */
|
||
BSP_Flash_Lock();
|
||
}
|
||
return STD_OK;
|
||
}
|
||
#endif
|
||
|
||
#if 0
|
||
static std_status_t Flash_WritePage(uint32_t addr, uint32_t *buf, size_t len)
|
||
{
|
||
std_status_t status = SUCCESS;
|
||
|
||
if ((addr & 0x03) != 0) // 地址4字节对齐
|
||
{
|
||
LOG_E("addr %#X is not aligned\r\n", addr);
|
||
return ERROR;
|
||
}
|
||
for (int i = 0; i < len; i++) // 页写入的WORD数
|
||
{
|
||
status = Flash_WriteWord((addr + i * sizeof(uint32_t)), *(buf + i * sizeof(uint32_t))); // 注意:地址增加应按uint32_t大小增加
|
||
if (status != SUCCESS)
|
||
{
|
||
return status; // 返回错误状态
|
||
}
|
||
}
|
||
return status; // 如果所有写入成功,返回SUCCESS
|
||
}
|
||
#endif
|
||
|
||
std_status_t Flash_ErasePage(uint32_t index)
|
||
{
|
||
std_flash_unlock();
|
||
RTT_LOG_D("ErasePage %d", index);
|
||
Flash_Interrupt_Disable();
|
||
std_status_t status = std_flash_erase(FLASH_ERASE_PAGE, index);
|
||
Flash_Interrupt_Enable();
|
||
std_flash_lock();
|
||
return status;
|
||
}
|
||
|
||
/**
|
||
* @description: 擦除产品信息页
|
||
* @return {*}
|
||
*/
|
||
void Flash_ErasePage_ConfigInfo(void)
|
||
{
|
||
if (Flash_ErasePage(FLASH_HR_INFO_PAGE) != SUCCESS)
|
||
{
|
||
RTT_LOG_E("error_page = %#x\r\n");
|
||
}
|
||
}
|
||
|
||
ErrorStatus BSP_Flash_Program_InfoPage(uint32_t address, uint32_t *data_buf)
|
||
{
|
||
ErrorStatus ret = ERROR;
|
||
|
||
for (uint32_t i = 0; i < FLASH_PAGE_RECORD_WORD_NUM; i++)
|
||
{
|
||
ret = Flash_WriteWord(address + i * 4, data_buf[i]);
|
||
if (ret != SUCCESS)
|
||
{
|
||
LOG_E("BSP_Flash_Program_InfoPage failed");
|
||
return ERROR;
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @description: 写产品信息页(最后一页)
|
||
* @param {uint8_t*} frame
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus Flash_Write_ConfigInfo(uint32_t *buf)
|
||
{
|
||
return BSP_Flash_Program_InfoPage(FLASH_CONFIG_INFO_START_ADDR, buf);
|
||
}
|
||
|
||
/*获取当前页号*/
|
||
uint32_t Flash_Get_Current_Page(uint32_t addr)
|
||
{
|
||
return (addr - FLASH_START_ADDR) / FLASH_PAGE_BYTE_SIZE;
|
||
}
|
||
|
||
/**
|
||
* @description: 擦除历史记录区的页
|
||
* @param {TeRecord} addr 需要擦除的页相对于其项目起始页的偏移量
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus Flash_ErasePage_Records(TeRecord record, uint8_t page_offset)
|
||
{
|
||
ErrorStatus flag = SUCCESS;
|
||
|
||
uint8_t erase_page = Flash_Get_Current_Page(hr_start_addr[record] + page_offset * FLASH_PAGE_BYTE_SIZE);
|
||
|
||
if (erase_page != hr_record_start_page_num[record] + page_offset)
|
||
{
|
||
RTT_LOG_E("Flash_ErasePage_Records failed erase_page: %#X != %#X",
|
||
erase_page, hr_record_start_page_num[record] + page_offset);
|
||
|
||
return ERROR;
|
||
}
|
||
if (Flash_ErasePage(erase_page) != SUCCESS)
|
||
{
|
||
RTT_LOG_E("Flash_ErasePage failed\r\n");
|
||
|
||
return ERROR;
|
||
}
|
||
for (uint16_t i = 0; i < FLASH_PAGE_BYTE_SIZE; i++) // 检查擦除是否完整
|
||
{
|
||
if (*(uint32_t *)((hr_start_addr[record] + FLASH_PAGE_BYTE_SIZE * erase_page) + i) != FLASH_DEFAULT_VALUE)
|
||
{
|
||
RTT_LOG_E("Flash_ErasePage failed\r\n");
|
||
|
||
return ERROR;
|
||
}
|
||
}
|
||
|
||
return flag;
|
||
}
|
||
|
||
/**
|
||
* @description: 擦除数据记录区
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus BSP_Flash_EraseRecodrs(void)
|
||
{
|
||
|
||
/*擦除所有的历史记录区*/
|
||
for (TeRecord record = kRecordAlarm; record < kRecordSensorFailure; record++)
|
||
{
|
||
for (uint8_t i = 0; i < hr_record_pages[record]; i++)
|
||
{
|
||
if (Flash_ErasePage(hr_record_start_page_num[record] + i) != SUCCESS)
|
||
{
|
||
RTT_LOG_E("Flash_ErasePage_Records failed\r\n");
|
||
|
||
return ERROR;
|
||
}
|
||
}
|
||
}
|
||
return SUCCESS;
|
||
}
|
||
/**
|
||
* @description: 先读再擦,以确保原有数据不会被擦除
|
||
* @param {uint8_t} *page_buf
|
||
* @return {*}
|
||
*/
|
||
void Flash_ErasePage_ReadConfigInfo(uint32_t *page_buf)
|
||
{
|
||
Flash_ReadWord(FLASH_CONFIG_INFO_START_ADDR, page_buf, FLASH_PAGE_RECORD_WORD_NUM);
|
||
Flash_ErasePage_ConfigInfo();
|
||
}
|
||
|
||
#if 1
|
||
/**
|
||
* @description: 获取产品的出厂或到期时间
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus Flash_GetProductTimeLimit(TuFlashHrRecordFrame *pLimitTime, TeFlashProductTimeLimitId id)
|
||
{
|
||
if (id == kFactoryTimeId)
|
||
{
|
||
pLimitTime->hr_data = *(uint32_t *)FLASH_FACTORY_TIME_ADDR;
|
||
|
||
if (pLimitTime->hr_data == FLASH_DEFAULT_VALUE)
|
||
{
|
||
RTT_LOG_E("FactoryTime is not set\r\n");
|
||
|
||
return ERROR;
|
||
}
|
||
if (pLimitTime->time.check_sum != Sum_Check(*pLimitTime))
|
||
{
|
||
RTT_LOG_E("FactoryTime check_sum error\r\n");
|
||
return ERROR;
|
||
}
|
||
RTT_LOG_D("Flash_Read_FactoryTime:%04d-%02d-%02d,%02d:%02d",
|
||
BASE_YEAR + pLimitTime->time.year, pLimitTime->time.month, pLimitTime->time.day,
|
||
pLimitTime->time.hour, pLimitTime->time.minute);
|
||
return SUCCESS;
|
||
}
|
||
else if (id == kExpirationTimeId)
|
||
{
|
||
pLimitTime->hr_data = *(uint32_t *)FLASH_EXPIRATION_TIME_ADDR;
|
||
if (pLimitTime->hr_data == FLASH_DEFAULT_VALUE)
|
||
{
|
||
RTT_LOG_E("ExpirationTime is not set\r\n");
|
||
|
||
return ERROR;
|
||
}
|
||
if (pLimitTime->time.check_sum != Sum_Check(*pLimitTime))
|
||
{
|
||
RTT_LOG_E("ExpirationTime check_sum error\r\n");
|
||
return ERROR;
|
||
}
|
||
RTT_LOG_D("Flash_Read_ExpirationTime:%04d-%02d-%02d,%02d:%02d",
|
||
BASE_YEAR + pLimitTime->time.year, pLimitTime->time.month, pLimitTime->time.day,
|
||
pLimitTime->time.hour, pLimitTime->time.minute);
|
||
return SUCCESS;
|
||
}
|
||
|
||
return ERROR;
|
||
}
|
||
|
||
/**
|
||
* @description: 设置产品的出厂或到期时间
|
||
* @param {uint16_t} year
|
||
* @param {uint8_t} mon
|
||
* @param {uint8_t} day
|
||
* @param {uint8_t} hour
|
||
* @param {uint8_t} min
|
||
* @param {TeFlashProductTimeLimitId} id
|
||
* @return {*}
|
||
*/
|
||
void Flash_SetProductTimeLimit(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, TeFlashProductTimeLimitId id)
|
||
{
|
||
TuFlashHrRecordFrame LimitTime;
|
||
TuFlashHrRecordFrame ReadLimitTime;
|
||
uint32_t page_buf[FLASH_PAGE_RECORD_WORD_NUM] = {0}; // 暂存最后一页的值
|
||
|
||
Flash_ErasePage_ReadConfigInfo(page_buf);
|
||
|
||
// page_buf[kFlashInitFlag] = FLASH_FIRST_INIT_VALUE;
|
||
|
||
LimitTime.time.year = year - BASE_YEAR;
|
||
LimitTime.time.month = mon;
|
||
LimitTime.time.day = day;
|
||
LimitTime.time.hour = hour;
|
||
LimitTime.time.minute = min;
|
||
LimitTime.time.check_sum = Sum_Check(LimitTime);
|
||
|
||
if (id == kFactoryTimeId)
|
||
{
|
||
page_buf[kFlashFactoryTime] = LimitTime.hr_data;
|
||
}
|
||
else if (id == kExpirationTimeId)
|
||
{
|
||
page_buf[kFlashExpirationTime] = LimitTime.hr_data;
|
||
}
|
||
// RTT_LOG_D("Flash_SetProductTimeLimit((%d)):%04d-%02d-%02d,%02d:%02d ", id, year, mon, day, hour, min);
|
||
Flash_Write_ConfigInfo(&page_buf[0]);
|
||
Flash_GetProductTimeLimit(&ReadLimitTime, id);
|
||
}
|
||
|
||
#endif
|
||
|
||
uint32_t ProductTimeLimit(uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min)
|
||
{
|
||
TuFlashHrRecordFrame LimitTime;
|
||
|
||
LimitTime.time.year = year - BASE_YEAR;
|
||
LimitTime.time.month = mon;
|
||
LimitTime.time.day = day;
|
||
LimitTime.time.hour = hour;
|
||
LimitTime.time.minute = min;
|
||
LimitTime.time.check_sum = Sum_Check(LimitTime);
|
||
|
||
return (uint32_t)LimitTime.hr_data;
|
||
}
|
||
|
||
/**
|
||
* @description: 产品信息初始化,
|
||
* @return {*}
|
||
*/
|
||
int BSP_Flash_Init(void)
|
||
{
|
||
|
||
if (*(uint32_t *)FLASH_CONFIG_INFO_START_ADDR != FLASH_FIRST_INIT_VALUE)
|
||
{
|
||
uint32_t info_page_buf[FLASH_PAGE_RECORD_WORD_NUM] = {0};
|
||
|
||
// TODO: 此处需要完善,比如写入初始化标志位,写入产品信息,写入出厂时间,写入到期时间
|
||
|
||
info_page_buf[kFlashInitFlag] = FLASH_FIRST_INIT_VALUE;
|
||
|
||
info_page_buf[kFlashFactoryTime] = ProductTimeLimit(2024, 1, 2, 3, 4);
|
||
info_page_buf[kFlashExpirationTime] = ProductTimeLimit(2024 + 10, 1, 2, 3, 4);
|
||
info_page_buf[kFlashLowAlarmValue] = 0x0A;//10%LEL
|
||
info_page_buf[kFlashHighAlarmValue] = 0x32;//50%LEL
|
||
// info_page_buf[kFlashSoftwareVersion] = XXX;
|
||
// info_page_buf[kFlashHardwareVersion] = XXX;
|
||
// info_page_buf[kFlashCompanyName] = XXX;
|
||
// info_page_buf[kFlashUpdateTime] = XXX;
|
||
|
||
BSP_Flash_EraseRecodrs(); // 擦除历史数据区
|
||
Flash_ErasePage_ConfigInfo(); // 擦除配置信息
|
||
|
||
if (Flash_Write_ConfigInfo(info_page_buf) != STD_OK)
|
||
{
|
||
RTT_LOG_E("Flash_Write_ConfigInfo failed");
|
||
return RT_ERROR;
|
||
}
|
||
}
|
||
return RT_EOK;
|
||
}
|
||
INIT_ENV_EXPORT(BSP_Flash_Init);
|
||
|
||
#if 1
|
||
/**
|
||
* @description: 获取索引信息
|
||
* @param {TeRecord} record
|
||
* @return {*}
|
||
*/
|
||
TsRecordIndex Flash_GetIndex_Pos(TeRecord record)
|
||
{
|
||
uint32_t index_addr = RT_NULL;
|
||
TsRecordIndex Index_Frame = {0};
|
||
|
||
uint32_t start_addr_default = hr_start_addr[record];
|
||
uint32_t hr_record_pages_default = hr_record_pages[record];
|
||
|
||
for (uint8_t page = 1; page <= hr_record_pages_default; page++) // 遍历对应项的历史数据扇区
|
||
{
|
||
for (uint8_t i = 0; i < FLASH_HR_PAGE_RECORD_NUM; i++) // 获取扇区偏移量
|
||
{
|
||
index_addr = (start_addr_default + FLASH_PAGE_BYTE_SIZE * (page - 1) + HR_RECORD_FRAME_LEN * i);
|
||
if (*(uint32_t *)index_addr == FLASH_DEFAULT_VALUE)
|
||
{
|
||
/*获取最新的数据所在位置,如果值为0xFFFFFFFF,则表示该页有空位,是最新的页*/
|
||
if (page < hr_record_pages_default) // 当前页不是最后一页
|
||
{
|
||
if (*(uint32_t *)(index_addr + FLASH_PAGE_BYTE_SIZE) == FLASH_DEFAULT_VALUE)
|
||
{
|
||
/* 没进行循环写入*/
|
||
Index_Frame.hr_start_addr = start_addr_default;
|
||
Index_Frame.hr_index_addr = index_addr;
|
||
Index_Frame.hr_num = (index_addr - start_addr_default) / HR_RECORD_FRAME_LEN;
|
||
Index_Frame.hr_page = page;
|
||
|
||
return Index_Frame;
|
||
}
|
||
else // 已经开始循环了
|
||
{
|
||
Index_Frame.hr_start_addr = (index_addr + FLASH_PAGE_BYTE_SIZE);
|
||
Index_Frame.hr_index_addr = index_addr;
|
||
Index_Frame.hr_num = hr_record_max_num[record];
|
||
Index_Frame.hr_page = page;
|
||
|
||
return Index_Frame;
|
||
}
|
||
}
|
||
else // 当前页是最后一页,那么首地址应该在第一页,其偏移量是最后一页的偏移量
|
||
{
|
||
Index_Frame.hr_start_addr = (start_addr_default + HR_RECORD_FRAME_LEN * i);
|
||
Index_Frame.hr_index_addr = index_addr;
|
||
Index_Frame.hr_num = hr_record_max_num[record];
|
||
Index_Frame.hr_page = page;
|
||
if (page == 1) // 只有一条数据,则索引地址应该在第一页
|
||
{
|
||
Index_Frame.hr_start_addr = start_addr_default;
|
||
Index_Frame.hr_index_addr = Index_Frame.hr_start_addr;
|
||
if (*(uint32_t *)(start_addr_default) == FLASH_DEFAULT_VALUE)
|
||
{
|
||
Index_Frame.hr_num = 0;
|
||
}
|
||
}
|
||
|
||
return Index_Frame;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
RTT_LOG_E("Flash_GetIndex_Pos Error!");
|
||
return Index_Frame;
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* @description:
|
||
* @param {TuFlashHrRecordFrame} *pHrRecord
|
||
* @param {TeRecord} record
|
||
* @param {uint8_t} index
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus Flash_Read_Record(TuFlashHrRecordFrame *pHrRecord, TeRecord record, size_t index)
|
||
{
|
||
uint32_t index_addr = 0;
|
||
TuFlashHrRecordFrame RecoderFrame = {0};
|
||
TsRecordIndex Index_Frame = Flash_GetIndex_Pos(record); // 已存储的数量
|
||
|
||
uint32_t start_addr_default = hr_start_addr[record];
|
||
uint32_t hr_record_pages_default = hr_record_pages[record];
|
||
uint8_t sum_check = 0;
|
||
if ((index <= hr_record_max_num[record]) && (index > 0))
|
||
{
|
||
if (index <= Index_Frame.hr_num)
|
||
{
|
||
{
|
||
if (Index_Frame.hr_start_addr == start_addr_default) // 是默认的起始地址,则读取数据就是对应的偏移量
|
||
{
|
||
index_addr = start_addr_default + (index - 1) * HR_RECORD_FRAME_LEN;
|
||
}
|
||
else
|
||
{
|
||
if ((Index_Frame.hr_start_addr + index * HR_RECORD_FRAME_LEN) <=
|
||
hr_record_pages_default * FLASH_PAGE_BYTE_SIZE + start_addr_default) // 没超过所在项目的页最大地址,正常读取,此时应该在缓存页
|
||
{
|
||
RTT_LOG_D("read :hr_start_addr1 = %#x", Index_Frame.hr_start_addr);
|
||
index_addr = Index_Frame.hr_start_addr + (index - 1) * HR_RECORD_FRAME_LEN;
|
||
}
|
||
else // 超过了所在项目的最大地址
|
||
{
|
||
RTT_LOG_D("read :hr_start_addr2 = %#x", Index_Frame.hr_start_addr);
|
||
index_addr = (Index_Frame.hr_start_addr + (index - 1) * HR_RECORD_FRAME_LEN - hr_record_pages[record] * FLASH_PAGE_BYTE_SIZE);
|
||
}
|
||
}
|
||
}
|
||
{
|
||
RecoderFrame.hr_data = (*(uint32_t *)index_addr);
|
||
sum_check = Sum_Check(RecoderFrame);
|
||
|
||
if (RecoderFrame.time.check_sum == sum_check)
|
||
{
|
||
pHrRecord->hr_data = RecoderFrame.hr_data; // 赋值后读出,看对不对
|
||
|
||
RTT_LOG_D("Flash_Read_(%d)Record(%d):%04d-%02d-%02d,%02d:%02d", record, index,
|
||
BASE_YEAR + pHrRecord->time.year, pHrRecord->time.month, pHrRecord->time.day,
|
||
pHrRecord->time.hour, pHrRecord->time.minute);
|
||
|
||
RTT_LOG_D("read :hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, read_data : %#X\r\n",
|
||
Index_Frame.hr_start_addr, index_addr, Index_Frame.hr_num, Index_Frame.hr_page, pHrRecord->hr_data);
|
||
|
||
return SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
RTT_LOG_E("read :hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, read_data : %#X",
|
||
Index_Frame.hr_start_addr, index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data);
|
||
|
||
RTT_LOG_E("Flash_GetMaxNum((%d)_Records(%d) Sum_Check(%#X) != check_sum(%#X),index_addr :%#X\r\n",
|
||
Index_Frame.hr_num, record, sum_check, RecoderFrame.time.check_sum, index_addr);
|
||
|
||
pHrRecord->hr_data = 0;
|
||
|
||
return ERROR;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
RTT_LOG_E("index num (%d) > Actual storage num %d", index, Index_Frame.hr_num);
|
||
pHrRecord->hr_data = 0;
|
||
return ERROR;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
RTT_LOG_E("index num (%d) > hr record max num %d && index > 0", index, hr_record_max_num[record]);
|
||
pHrRecord->hr_data = 0;
|
||
return ERROR;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description: 向对应的历史数据存储区写入一次数据
|
||
* @param {TeRecord} record
|
||
* @return {*}
|
||
*/
|
||
ErrorStatus Flash_Write_Record(TeRecord record)
|
||
{
|
||
TsRecordIndex Index_Frame;
|
||
TuFlashHrRecordFrame RecoderFrame = {0};
|
||
// uint8_t rtctime[3] = {0}, rtcdate[3] = {0};
|
||
|
||
if (record == kRecordSensorFailure && *(uint32_t *)hr_start_addr[record] != FLASH_DEFAULT_VALUE) // 传感器故障记录,且已经写入过数据,则不再写入
|
||
{
|
||
RecoderFrame.hr_data = *(uint32_t *)hr_start_addr[record];
|
||
|
||
RTT_LOG_E("Flash_Write_(%d)Record(%d) num >= recorded Max num(%d)", record, Index_Frame.hr_num, hr_record_max_num[record]);
|
||
|
||
Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num); // 读取刚才写入数据
|
||
|
||
return ERROR;
|
||
}
|
||
// __cycleof__("my algorithm")
|
||
// {
|
||
// BSP_Rtc_Get_Calendar(rtcdate, rtctime);
|
||
// }
|
||
Index_Frame = Flash_GetIndex_Pos(record);
|
||
/*这里可以使用RTC闹钟,每分钟更新一次数据,这样只需要从缓存读取数据就行,降低了访问的时间*/
|
||
RecoderFrame.time.hour = std_rtc_convert_bcd2bin(rtctime[0]); // h
|
||
RecoderFrame.time.minute = std_rtc_convert_bcd2bin(rtctime[1]); // m
|
||
|
||
RecoderFrame.time.year = (std_rtc_convert_bcd2bin(rtcdate[0]) - 24); // y
|
||
RecoderFrame.time.month = std_rtc_convert_bcd2bin(rtcdate[1]); // m
|
||
RecoderFrame.time.day = std_rtc_convert_bcd2bin(rtcdate[2]); // d
|
||
RecoderFrame.time.check_sum = Sum_Check(RecoderFrame);
|
||
|
||
// RTT_LOG_D("sizof TuFlashHrRecordFrame(%d)", sizeof(TuFlashHrRecordFrame));
|
||
|
||
RTT_LOG_D("write:hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X",
|
||
Index_Frame.hr_start_addr, Index_Frame.hr_index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data);
|
||
|
||
RTT_LOG_D("Flash_Write_(%d)Record:%04d-%02d-%02d %02d:%02d, check_sum : %#X",
|
||
record, RecoderFrame.time.year + BASE_YEAR, RecoderFrame.time.month, RecoderFrame.time.day,
|
||
RecoderFrame.time.hour, RecoderFrame.time.minute, RecoderFrame.time.check_sum);
|
||
{
|
||
/*写入数据*/
|
||
|
||
if (Flash_WriteWord(Index_Frame.hr_index_addr, RecoderFrame.hr_data) != SUCCESS)
|
||
{
|
||
RTT_LOG_E("hr_write_data_error");
|
||
RTT_LOG_E("hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X",
|
||
Index_Frame.hr_start_addr, Index_Frame.hr_index_addr, Index_Frame.hr_num, Index_Frame.hr_page, RecoderFrame.hr_data);
|
||
|
||
return ERROR;
|
||
}
|
||
}
|
||
{
|
||
/*如果把当前页写完了,要把下一页擦了,这样索引才不会出错,否则会导致索引出错*/
|
||
if (Index_Frame.hr_index_addr == hr_start_addr[record] + (Index_Frame.hr_page) * FLASH_PAGE_BYTE_SIZE - HR_RECORD_FRAME_LEN)
|
||
{
|
||
RTT_LOG_I("Index_Frame.hr_index_addr = hr_start_addr[record] + i * FLASH_PAGE_BYTE_SIZE - HR_RECORD_FRAME_LEN = %#X", Index_Frame.hr_index_addr);
|
||
if (hr_record_pages[record] - Index_Frame.hr_page > 0) // 当前页不是最后一页,还不需要返回擦
|
||
{
|
||
if (Flash_ErasePage(Index_Frame.hr_page + hr_record_start_page_num[record]) != SUCCESS)
|
||
{
|
||
RTT_LOG_I("Erase Page %d", Index_Frame.hr_page + hr_record_start_page_num[record]);
|
||
return ERROR;
|
||
}
|
||
}
|
||
else // 当前页是最后一页 此时需要将第一页擦除掉
|
||
{
|
||
if (Flash_ErasePage(hr_record_start_page_num[record]) != SUCCESS) // 擦除第一页
|
||
{
|
||
RTT_LOG_I("Erase Page %d", hr_record_start_page_num[record]);
|
||
return ERROR;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
{
|
||
if (Index_Frame.hr_num < hr_record_max_num[record])
|
||
{
|
||
|
||
Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num + 1); // 读取刚才写入数据,此时这个hr_num实际上是会+1的,当到达最大计数之前,hr_num会+1,到了以后,就默认是最大数量条数据,所以不用加
|
||
}
|
||
else // 超了最大数后,每次读出来的数据都是最大数
|
||
{
|
||
Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num); // 读取刚才写入数据
|
||
}
|
||
}
|
||
|
||
return SUCCESS;
|
||
}
|
||
|
||
static void TEST_Flash_Write_Record(int argc, char **argv)
|
||
{
|
||
|
||
if (argc == 3)
|
||
{
|
||
TeRecord record = (TeRecord)atoi(argv[1]);
|
||
int num = atoi(argv[2]);
|
||
|
||
for (int i = 1; i <= num; i++)
|
||
{
|
||
RTT_LOG_I("Flash_Write_(%d)Record:%d", record, i);
|
||
Flash_Write_Record(record);
|
||
rt_thread_mdelay(1000 * 60); // 1min
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LOG_E("TEST_Flash_Write_Record --use _cmd_ [record(0~6)] [num]");
|
||
}
|
||
}
|
||
MSH_CMD_EXPORT(TEST_Flash_Write_Record, "TEST_Flash_Write_Record");
|
||
|
||
static void TEST_Flash_Read_Record(int argc, char **argv)
|
||
{
|
||
TuFlashHrRecordFrame RecoderFrame = {0};
|
||
|
||
if (argc == 3)
|
||
{
|
||
TeRecord record = (TeRecord)atoi(argv[1]);
|
||
int num = atoi(argv[2]);
|
||
Flash_Read_Record(&RecoderFrame, record, num);
|
||
}
|
||
else
|
||
{
|
||
LOG_E("TEST_Flash_Read_Record --use _cmd_ [record(0~6)] [num]");
|
||
}
|
||
}
|
||
MSH_CMD_EXPORT(TEST_Flash_Read_Record, "TEST_Flash_Read_Record");
|
||
|
||
/*获取当前项目记录数*/
|
||
uint8_t Flash_GetNum_Records(TeRecord record)
|
||
{
|
||
TsRecordIndex Index_Frame = Flash_GetIndex_Pos(record);
|
||
|
||
return Index_Frame.hr_num;
|
||
}
|
||
|
||
/**
|
||
* @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;
|
||
uint16_t years = 0;
|
||
|
||
if (kNumOfRecords < record_type && record_type < kGetCurrentTime)
|
||
{
|
||
TuFlashHrRecordFrame pHrReadRecord;
|
||
/*这里存在多种情况,其中最常见的就是没有记录,,所有情况的结果就是此基数年不存在*/
|
||
if (Flash_Read_Record(&pHrReadRecord, (TeRecord)(record_type - 1), index) != SUCCESS)
|
||
{
|
||
years = pHrReadRecord.time.year;
|
||
}
|
||
else
|
||
{
|
||
years = BASE_YEAR + pHrReadRecord.time.year;
|
||
}
|
||
LOG_D("(%d)Flash_GetRecord[%d]:%04d-%02d-%02d,%02d:%02d",
|
||
record_type - 1, index,
|
||
years, pHrReadRecord.time.month, pHrReadRecord.time.day,
|
||
pHrReadRecord.time.hour, pHrReadRecord.time.minute);
|
||
|
||
pRecordsTime->year_h = years / 256;
|
||
pRecordsTime->year_l = years % 256;
|
||
pRecordsTime->month = pHrReadRecord.time.month;
|
||
pRecordsTime->day = pHrReadRecord.time.day;
|
||
pRecordsTime->hour = pHrReadRecord.time.hour;
|
||
pRecordsTime->minute = pHrReadRecord.time.minute;
|
||
|
||
flag = SUCCESS;
|
||
}
|
||
|
||
return flag;
|
||
}
|