2024-08-31 10:27:58 +08:00
|
|
|
|
/*
|
|
|
|
|
* @Author: mbw
|
|
|
|
|
* @Date: 2024-08-22 16:15:08
|
|
|
|
|
* @LastEditors: mbw && 1600520629@qq.com
|
2024-08-31 14:50:41 +08:00
|
|
|
|
* @LastEditTime: 2024-08-31 14:29:26
|
2024-08-31 10:27:58 +08:00
|
|
|
|
* @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 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};
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
/*定义历史数据所在的真实起始页*/
|
2024-08-31 10:27:58 +08:00
|
|
|
|
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};
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
// 定义常量
|
|
|
|
|
#define CHECKSUM_MASK 0xFF
|
|
|
|
|
|
|
|
|
|
// 数据帧结构体
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
uint32_t headerIndexChecksum; // 帧头、索引和校验和
|
|
|
|
|
uint32_t timestamp; // 时间戳
|
|
|
|
|
} DataFrame;
|
|
|
|
|
|
|
|
|
|
static rt_base_t interrupt_value;
|
|
|
|
|
static void BSP_Flash_UnLock(void)
|
|
|
|
|
{
|
|
|
|
|
interrupt_value = rt_hw_interrupt_disable();
|
|
|
|
|
|
|
|
|
|
/* Flash控制寄存器解锁 */
|
|
|
|
|
std_flash_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void BSP_Flash_Lock(void)
|
|
|
|
|
{
|
|
|
|
|
/* Flash控制寄存器加锁 */
|
|
|
|
|
std_flash_lock();
|
|
|
|
|
|
|
|
|
|
rt_hw_interrupt_enable(interrupt_value);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
// 计算校验和的函数
|
|
|
|
|
uint8_t Sum_Check(TuFlashHrRecordFrame frame)
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
return (frame.time.year + frame.time.month + frame.time.day + frame.time.hour + frame.time.minute) & CHECKSUM_MASK;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
/// @brief
|
|
|
|
|
/// @param addr
|
|
|
|
|
/// @param buf
|
|
|
|
|
/// @param len
|
|
|
|
|
/// @param mode 选择读的大小 字节 半字 字
|
|
|
|
|
/// @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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (std_flash_word_program(addr, write_data) != SUCCESS) // 写入操作 字节写入
|
|
|
|
|
{
|
|
|
|
|
LOG_D("addr = %#X, read %d", addr, *(uint32_t *)addr);
|
|
|
|
|
BSP_Flash_Lock();
|
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
BSP_Flash_Lock();
|
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
2024-08-31 14:50:41 +08:00
|
|
|
|
rt_thread_mdelay(2);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BSP_Flash_Lock();
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std_status_t Flash_WritePage(uint32_t addr, uint32_t *buf)
|
|
|
|
|
{
|
|
|
|
|
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 < FLASH_HR_PAGE_NUM; i++) // 页写入的WORD数
|
|
|
|
|
{
|
|
|
|
|
status = Flash_WriteWord((addr + i * sizeof(uint32_t)), *(buf + i)); // 注意:地址增加应按uint32_t大小增加
|
|
|
|
|
if (status != SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
return status; // 返回错误状态
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status; // 如果所有写入成功,返回SUCCESS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description: 擦除产品信息页
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
void Flash_ErasePage_ConfigInfo(void)
|
|
|
|
|
{
|
|
|
|
|
if (std_flash_page_erase(127) != SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
LOG_D("error_page = %#x\r\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description: 写产品信息页(最后一页)
|
|
|
|
|
* @param {uint8_t*} frame
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
void Flash_Write_ConfigInfo(uint32_t *frame)
|
|
|
|
|
{
|
|
|
|
|
Flash_WritePage(FLASH_CONFIG_INFO_START_ADDR, frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*获取当前页号*/
|
|
|
|
|
uint32_t Flash_Get_Current_Page(uint32_t addr)
|
|
|
|
|
{
|
|
|
|
|
return (addr - FLASH_START_ADDR) / FLASH_PAGE_BYTE_SIZE;
|
|
|
|
|
}
|
|
|
|
|
std_status_t Flash_ErasePage(uint32_t index)
|
|
|
|
|
{
|
|
|
|
|
BSP_Flash_UnLock();
|
|
|
|
|
RTT_LOG_D("ErasePage %d", index);
|
|
|
|
|
std_status_t status = std_flash_erase(FLASH_ERASE_PAGE, index);
|
|
|
|
|
BSP_Flash_Lock();
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @description: 擦除历史记录区的页
|
|
|
|
|
* @param {TeRecord} addr 需要擦除的页的起始地址
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
static ErrorStatus Flash_ErasePage_Records(TeRecord record, uint8_t page_offset)
|
|
|
|
|
{
|
|
|
|
|
ErrorStatus flag = SUCCESS;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Flash_ErasePage(Flash_Get_Current_Page(hr_start_addr[record] + erase_page * FLASH_PAGE_BYTE_SIZE)) != SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
flag = ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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_BYTE_SIZE);
|
|
|
|
|
Flash_ErasePage_ConfigInfo();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
#if 1
|
2024-08-31 10:27:58 +08:00
|
|
|
|
/**
|
|
|
|
|
* @description: 获取产品的出厂或到期时间
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
2024-08-31 14:50:41 +08:00
|
|
|
|
ErrorStatus Flash_GetProductTimeLimit(TuFlashHrRecordFrame *pLimitTime, TeFlashProductTimeLimitId id)
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
|
|
|
|
ErrorStatus flag = ERROR;
|
|
|
|
|
uint32_t addr = 0;
|
2024-08-31 14:50:41 +08:00
|
|
|
|
if (id >= kMaxNum)
|
|
|
|
|
{
|
|
|
|
|
LOG_E("id %d is not supported\r\n", id);
|
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
if (id == kFactoryTimeId)
|
|
|
|
|
{
|
|
|
|
|
addr = FLASH_FACTORY_TIME_START_ADDR;
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
else if (id == kExpirationTimeId)
|
|
|
|
|
{
|
|
|
|
|
addr = FLASH_EXPIRATION_TIME_START_ADDR;
|
|
|
|
|
}
|
|
|
|
|
if (addr != 0)
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
pLimitTime->hr_data = *(uint32_t *)addr;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/**
|
|
|
|
|
* @description: 产品信息初始化,
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
void BSP_Flash_Init(void)
|
|
|
|
|
{
|
|
|
|
|
if (*(uint32_t *)FLASH_CONFIG_INFO_START_ADDR != FLASH_FIRST_INIT_VALUE)
|
|
|
|
|
{
|
|
|
|
|
uint32_t info_page_buf[128] = {0};
|
|
|
|
|
BSP_Flash_EraseRecodrs(); // 擦除历史数据区
|
|
|
|
|
// TODO: 此处需要完善,比如写入初始化标志位,写入产品信息,写入出厂时间,写入到期时间,
|
|
|
|
|
Flash_WritePage(FLASH_CONFIG_INFO_START_ADDR, info_page_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
#if 1
|
2024-08-31 10:27:58 +08:00
|
|
|
|
/**
|
|
|
|
|
* @description: 获取索引起始地址
|
|
|
|
|
* @param {TeRecord} record
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
TsRecordIndex Flash_GetIndex_Pos(TeRecord record)
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
uint32_t index_addr = RT_NULL;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
TsRecordIndex Index_Frame = {0};
|
|
|
|
|
|
|
|
|
|
for (uint8_t page = 1; page <= hr_record_pages[record]; page++) // 遍历对应项的历史数据扇区
|
|
|
|
|
{
|
|
|
|
|
for (uint8_t i = 0; i < FLASH_HR_PAGE_RECORD_NUM; i++) // 获取扇区偏移量
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
index_addr = (hr_start_addr[record] + FLASH_PAGE_BYTE_SIZE * (page - 1) + HR_RECORD_FRAME_LEN * i);
|
|
|
|
|
if (*(uint32_t *)index_addr == FLASH_DEFAULT_VALUE)
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
|
|
|
|
/*获取最新的数据所在位置,如果值为0xFFFFFFFF,则表示该页有空位,是最新的页*/
|
|
|
|
|
if (page < hr_record_pages[record]) // 当前页不是最后一页
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
if (*(uint32_t *)(index_addr + FLASH_PAGE_BYTE_SIZE) == FLASH_DEFAULT_VALUE)
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
|
|
|
|
/* 没进行循环写入*/
|
|
|
|
|
Index_Frame.hr_start_addr = hr_start_addr[record];
|
2024-08-31 14:50:41 +08:00
|
|
|
|
Index_Frame.hr_index_addr = index_addr;
|
|
|
|
|
Index_Frame.hr_num = (index_addr - hr_start_addr[record]) / HR_RECORD_FRAME_LEN;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
Index_Frame.hr_page = page;
|
|
|
|
|
|
|
|
|
|
return Index_Frame;
|
|
|
|
|
}
|
|
|
|
|
else // 已经开始循环了
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
Index_Frame.hr_start_addr = (index_addr + FLASH_PAGE_BYTE_SIZE);
|
|
|
|
|
Index_Frame.hr_index_addr = index_addr;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
Index_Frame.hr_num = hr_record_max_num[record];
|
|
|
|
|
Index_Frame.hr_page = page;
|
|
|
|
|
|
|
|
|
|
return Index_Frame;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // 当前页是最后一页,那么首地址应该在第一页,其偏移量是最后一页的偏移量
|
|
|
|
|
{
|
|
|
|
|
Index_Frame.hr_start_addr = (hr_start_addr[record] + HR_RECORD_FRAME_LEN * i);
|
2024-08-31 14:50:41 +08:00
|
|
|
|
Index_Frame.hr_index_addr = index_addr;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
Index_Frame.hr_num = hr_record_max_num[record];
|
|
|
|
|
Index_Frame.hr_page = page;
|
2024-08-31 14:50:41 +08:00
|
|
|
|
if (page == 1) // 只有一条数据,则索引地址应该在第一页
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
Index_Frame.hr_start_addr = hr_start_addr[record];
|
|
|
|
|
Index_Frame.hr_index_addr = Index_Frame.hr_start_addr;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
return Index_Frame;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RTT_LOG_E("Flash_GetIndex_Pos Error!");
|
|
|
|
|
return Index_Frame;
|
|
|
|
|
}
|
2024-08-31 14:50:41 +08:00
|
|
|
|
#endif
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description:
|
|
|
|
|
* @param {TuFlashHrRecordFrame} *pHrRecord
|
|
|
|
|
* @param {TeRecord} record
|
|
|
|
|
* @param {uint8_t} index
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
ErrorStatus Flash_Read_Record(TuFlashHrRecordFrame *pHrRecord, TeRecord record, size_t index)
|
|
|
|
|
{
|
|
|
|
|
// LOG_D("/*********************Flash_Read_Record**********************/");
|
2024-08-31 14:50:41 +08:00
|
|
|
|
uint32_t index_addr = 0;
|
|
|
|
|
TuFlashHrRecordFrame RecoderFrame = {0};
|
|
|
|
|
TsRecordIndex Index_Frame = Flash_GetIndex_Pos(record); // 已存储的数量
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
if (index <= hr_record_max_num[record])
|
|
|
|
|
{
|
|
|
|
|
if (index <= Index_Frame.hr_num)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
if (Index_Frame.hr_start_addr == hr_start_addr[record]) // 是默认的起始地址,则读取数据就是对应的偏移量
|
|
|
|
|
{
|
|
|
|
|
index_addr = hr_start_addr[record] + (index - 1) * HR_RECORD_FRAME_LEN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((Index_Frame.hr_start_addr + index * HR_RECORD_FRAME_LEN) <=
|
|
|
|
|
hr_record_pages[record] * FLASH_PAGE_BYTE_SIZE + hr_start_addr[record]) // 没超过所在项目的页最大地址,正常读取,此时应该在缓存页
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
RecoderFrame.hr_data = (*(uint32_t *)index_addr);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
if (RecoderFrame.time.check_sum == Sum_Check(RecoderFrame))
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
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);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
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, RecoderFrame.hr_data);
|
|
|
|
|
pHrRecord->hr_data = RecoderFrame.hr_data;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
RTT_LOG_E("Error data: %d-%d-%d,%d:%d", BASE_YEAR + RecoderFrame.time.year, RecoderFrame.time.month, RecoderFrame.time.day,
|
|
|
|
|
RecoderFrame.time.hour, RecoderFrame.time.minute);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
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);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
RTT_LOG_E("Flash_GetMaxNum((%d)_Records(%d) Sum_Check(%#X) != check_sum(%#X),index_addr :%#X\r\n",
|
2024-08-31 14:50:41 +08:00
|
|
|
|
Index_Frame.hr_num, record, Sum_Check(RecoderFrame), RecoderFrame.time.check_sum, index_addr);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
pHrRecord->hr_data = FLASH_DEFAULT_VALUE;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RTT_LOG_E("index num (%d) > Actual storage num %d", index, Index_Frame.hr_num);
|
|
|
|
|
|
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RTT_LOG_E("index num (%d) > hr record max num %d", index, hr_record_max_num[record]);
|
|
|
|
|
|
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description: 向对应的历史数据存储区写入一次数据
|
|
|
|
|
* @param {TeRecord} record
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
ErrorStatus Flash_Write_Record(TeRecord record)
|
|
|
|
|
{
|
|
|
|
|
uint8_t rtctime[3], rtcdate[3];
|
|
|
|
|
|
|
|
|
|
TuFlashHrRecordFrame RecoderFrame = {0};
|
|
|
|
|
|
|
|
|
|
TsRecordIndex Index_Frame;
|
|
|
|
|
|
|
|
|
|
Index_Frame = Flash_GetIndex_Pos(record);
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
// __cycleof__("my algorithm")
|
|
|
|
|
// {
|
|
|
|
|
BSP_Rtc_Get_Calendar(rtcdate, rtctime);
|
|
|
|
|
// }
|
|
|
|
|
if (record == kRecordSensorFailure && *(uint32_t *)hr_start_addr[record] != FLASH_DEFAULT_VALUE) // 传感器故障记录,且已经写入过数据,则不再写入
|
2024-08-31 10:27:58 +08:00
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
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); // 读取刚才写入数据
|
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
return ERROR;
|
|
|
|
|
}
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
|
|
|
|
/*这里可以使用RTC闹钟,每分钟更新一次数据,这样只需要从缓存读取数据就行,降低了访问的时间*/
|
2024-08-31 10:27:58 +08:00
|
|
|
|
RecoderFrame.time.year = (std_rtc_convert_bcd2bin(rtcdate[0]) - 24);
|
|
|
|
|
RecoderFrame.time.month = std_rtc_convert_bcd2bin(rtcdate[1]);
|
|
|
|
|
RecoderFrame.time.day = std_rtc_convert_bcd2bin(rtcdate[2]);
|
|
|
|
|
RecoderFrame.time.hour = std_rtc_convert_bcd2bin(rtctime[0]);
|
|
|
|
|
RecoderFrame.time.minute = std_rtc_convert_bcd2bin(rtctime[1]);
|
2024-08-31 14:50:41 +08:00
|
|
|
|
RecoderFrame.time.check_sum = Sum_Check(RecoderFrame);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
RTT_LOG_D("write:hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X",
|
2024-08-31 10:27:58 +08:00
|
|
|
|
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);
|
|
|
|
|
{
|
|
|
|
|
/*写入数据*/
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
2024-08-31 10:27:58 +08:00
|
|
|
|
if (Flash_WriteWord(Index_Frame.hr_index_addr, RecoderFrame.hr_data) != SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
RTT_LOG_E("hr_write_data_error");
|
2024-08-31 14:50:41 +08:00
|
|
|
|
RTT_LOG_E("hr_start_addr = %#x, index_addr: %#x, hr_num: %d, hr_page:%d, write_data : %#X",
|
2024-08-31 10:27:58 +08:00
|
|
|
|
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])
|
|
|
|
|
{
|
2024-08-31 14:50:41 +08:00
|
|
|
|
|
|
|
|
|
Flash_Read_Record(&RecoderFrame, record, Index_Frame.hr_num + 1); // 读取刚才写入数据,此时这个hr_num实际上是会+1的,当到达最大计数之前,hr_num会+1,到了以后,就默认是最大数量条数据,所以不用加
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
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]);
|
2024-08-31 14:50:41 +08:00
|
|
|
|
char *end;
|
|
|
|
|
uint32_t num = strtoul(argv[2], &end, 10);
|
|
|
|
|
;
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
for (int i = 1; i <= num; i++)
|
|
|
|
|
{
|
|
|
|
|
RTT_LOG_I("Flash_Write_(%d)Record:%d", record, i);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
Flash_Write_Record(record);
|
2024-08-31 14:50:41 +08:00
|
|
|
|
rt_thread_mdelay(500);
|
2024-08-31 10:27:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG_E("TEST_Flash_Write_Record --use _cmd_ [record(0~6)] [num]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MSH_CMD_EXPORT(TEST_Flash_Write_Record, "TEST_Flash_Write_Record");
|
|
|
|
|
|
2024-08-31 14:50:41 +08:00
|
|
|
|
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");
|
2024-08-31 10:27:58 +08:00
|
|
|
|
|
|
|
|
|
/*获取当前项目记录数*/
|
|
|
|
|
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;
|
|
|
|
|
Flash_Read_Record(&pHrReadRecord, (TeRecord)(record_type - 1), index);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
#endif
|