说明: 日志记录系统按照API封装的思想只在接口文件中保留功能性程序,及 init ,set ,get;存储器使用华邦的w25q64,最低擦除的为1个sector(4096Bytes);日志系统主要分为三个部分 1、日志索引 ,2、断电日志存储区,3、日志存储区
为了避免对单个地址持续擦写造成块损坏,日志索引使用两个sector作为日志的索引存储区,日志索引每写一次地址增加16字节。当开机初始化的时候按照一定的方法将最新的索引页读取出来,用于对日志记录的地址进行记录。
为了能够记录断电瞬间设备的运行情况,需要存储数据到断电日志区,等待下次开机后将断电日志记录到日志中。然后将断电日志区的数据擦除。
目前设计的是4096条日志数据,每条日志占用空间为64Bytes,考虑到增加器件寿命,每次写sector到的起始地址时将该sector擦除,然后将日志总长度减 64.
mod_logSysInfo.h
/**
*****************************************************************************
* @文 件: mod_logSysInfo.h
* @作 者: 00Jackey
* @版 本: V1.0.0
* @日 期: 5-Jun-2018
* @描 述: 日志信息系统接口文件
******************************************************************************
* @修改记录:
* 2018/06/05:初始版本
*
*
******************************************************************************
**/
#ifndef _MOD_LOGSYSINFO_H_
#define _MOD_LOGSYSINFO_H_
#ifdef _cplusplus
extern "C" {
#endif
//C库
#include
#include
#include
//宏定义
#define LOG_INDEX_TOTAL (uint32_t)(15)
#define EACH_INDEX_SPACE (uint32_t)(16)
#define LOG_CONTENT_TOTAL (uint32_t)(52)
#define EACH_LOG_SPACE (uint32_t)(64)
#define LOG_INFO_TOTAL_CNT (uint32_t)(4096)
#define LOG_WRITE_FLAG (uint8_t)(0xA5)
//定义枚举
typedef enum {
LOG_NOT_USE = 0,
LOG_BE_WRITE = 1,
LOG_BE_READ = 2
}LOG_OPERATE_STATE_ENUM;
typedef enum{
LOG_PROC_SUCCEED = 0,
LOG_PROC_FAILED = 1
}LOG_PROC_STATE_ENUM;
//定义结构体
typedef struct{
uint8_t dateArry[LOG_CONTENT_TOTAL];
uint32_t curNum;
uint32_t curTime;
uint16_t length;
uint8_t verifyVal;
uint8_t writeFlag;
}LOG_CONTENT_STRUCT;
//定义联合体
typedef union{
LOG_CONTENT_STRUCT ContentStruct;
uint8_t ConentArry[EACH_LOG_SPACE];
}LOG_CONTENT_UNION;
//定义结构体
typedef struct{
uint32_t curIndex;
uint32_t cntTotal;
uint32_t rawTotal;
uint8_t useless[3];
uint8_t writeFlag;
}LOG_INDEX_STRUCT;
//定义联合体
typedef union{
LOG_INDEX_STRUCT IndexStruct;
uint8_t IndexArry[LOG_INDEX_TOTAL+1];
}LOG_INDEX_UNION;
//函数封装
typedef struct
{
LOG_PROC_STATE_ENUM (*init)(void);
LOG_PROC_STATE_ENUM (*record)(LOG_CONTENT_UNION uLogInfoUnion);
LOG_PROC_STATE_ENUM (*getRecent)(LOG_CONTENT_UNION* pLogInfoUnion, int32_t recentNum);
LOG_PROC_STATE_ENUM (*getSerial)(LOG_CONTENT_UNION* pLogInfoUnion, int32_t serialNum);
}LOG_SYS_CONTENT_STRUCT;
typedef struct
{
LOG_PROC_STATE_ENUM (*clr)(void);
LOG_PROC_STATE_ENUM (*set)(LOG_CONTENT_UNION uLogInfoUnion);
LOG_PROC_STATE_ENUM (*get)(LOG_CONTENT_UNION* pLogInfoUnion);
}LOG_SYS_OUTAGE_STRUCT;
typedef struct
{
LOG_OPERATE_STATE_ENUM LogOperateFlag; //日志读、写、空闲状态
LOG_SYS_OUTAGE_STRUCT OutageStruct; //断电日志封装
LOG_SYS_CONTENT_STRUCT ContentStruct; //主日志封装
LOG_PROC_STATE_ENUM (*init)(void); //日志系统初始化
uint32_t (*getRawTotal)(void); //获取日志数量
}LOG_SYS_INFO_STRUCT;
//外部调用
extern LOG_SYS_INFO_STRUCT LogSysInfoStruct;
#ifdef _cplusplus
}
#endif
#endif
mod_logSysInfo.c
/**
*****************************************************************************
* @文 件: mod_logSysInfo.c
* @作 者: 00Jackey
* @版 本: V1.0.0
* @日 期: 6-Jun-2018
* @描 述: 日志信息系统主文件
******************************************************************************
* @修改记录:
* 2018/06/06:初始版本,待通信完成后做完整性测试
* 2018/07/01:做完完整性测试,改了一些问题
*
******************************************************************************
**/
//接口头文件
#include "mod_logSysInfo.h"
//硬件驱动
#include "hardware.h"
//宏定义
#define CHIPSET_PAGE (uint32_t)256
#define CHIPSET_SECTOR_SIZE (uint32_t)(CHIPSET_PAGE * 16)
#define CHIPSET_BLOCK_SIZE (uint32_t)(CHIPSET_SECTOR_SIZE * 16)
#define CHIPSET_TOTAL_SIZE (uint32_t)(CHIPSET_BLOCK_SIZE * 128)
#define LOG_SYS_OUTAGE_ADDRESS (uint32_t)(CHIPSET_SECTOR_SIZE * 13)
#define LOG_SYS_INDEX_ADDRESS (uint32_t)(CHIPSET_SECTOR_SIZE * 14)
#define LOG_SYS_INFO_ADDRESS (uint32_t)(CHIPSET_SECTOR_SIZE * 16)
#define LOG_SYS_INFO_TOAL_SIZE (uint32_t)(LOG_INFO_TOTAL_CNT * EACH_LOG_SPACE)
#define LOG_SYS_INDEX_TOAL_SIZE (uint32_t)(CHIPSET_SECTOR_SIZE * 2)
#define LOG_SYS_WRITE W25qxx_writeBuffer
#define LOG_SYS_READ W25qxx_readBuffer
#define LOG_SYS_ERASE W25qxx_eraseOneSector
#define LOG_INDEX_ADDR sLogIndexAddr
//静态函数
static LOG_PROC_STATE_ENUM LogSysInfo_initInfo(void);
static LOG_PROC_STATE_ENUM LogSysInfo_recordInfo(LOG_CONTENT_UNION uLogContentUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getRecentInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t recentNum);
static LOG_PROC_STATE_ENUM LogSysInfo_getSerialInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t serialNum);
static LOG_PROC_STATE_ENUM LogSysInfo_initIndex(void);
static LOG_PROC_STATE_ENUM LogSysInfo_setIndex(LOG_INDEX_UNION uLogIndexUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getIndex(LOG_INDEX_UNION* pLogIndexUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_clrOutage(void);
static LOG_PROC_STATE_ENUM LogSysInfo_setOutage(LOG_CONTENT_UNION uLogContentUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getOutage(LOG_CONTENT_UNION* pLogContentUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_init(void);
static uint32_t LogSysInfo_getRawTotal(void);
static uint8_t LogSysInfo_calcXor8(uint8_t *pVarArry, uint8_t len);
//常量
const LOG_INDEX_UNION cDefaultLogIndexUnion = {
.IndexStruct.curIndex = (LOG_SYS_INFO_ADDRESS - EACH_LOG_SPACE),
.IndexStruct.cntTotal = 0,
.IndexStruct.rawTotal = 0,
.IndexStruct.writeFlag = LOG_WRITE_FLAG,
};
//静态变量
LOG_INDEX_UNION sLogIndexUnion;
uint32_t sLogIndexAddr;
//全局变量
LOG_SYS_INFO_STRUCT LogSysInfoStruct = {
.ContentStruct.init = LogSysInfo_initInfo,
.ContentStruct.record = LogSysInfo_recordInfo,
.ContentStruct.getRecent = LogSysInfo_getRecentInfo,
.ContentStruct.getSerial = LogSysInfo_getSerialInfo,
.OutageStruct.clr = LogSysInfo_clrOutage,
.OutageStruct.set = LogSysInfo_setOutage,
.OutageStruct.get = LogSysInfo_getOutage,
.init = LogSysInfo_init,
.getRawTotal = LogSysInfo_getRawTotal,
};
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_init
* 功能说明: 日志系统初始化
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_init(void)
{
if(LOG_PROC_FAILED == LogSysInfo_initIndex())
return LOG_PROC_FAILED;
else
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_getRawTotal
* 功能说明: 获取日志中所存储的日志数量
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
uint32_t LogSysInfo_getRawTotal(void)
{
return sLogIndexUnion.IndexStruct.rawTotal;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_initIndex
* 功能说明: 日志索引初始化
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_initIndex(void)
{
LOG_PROC_STATE_ENUM rState;
LOG_INDEX_UNION tLogIndexUnion;
int32_t i_reord = -1;
/* 遍历第一个块,判断每个位置是否都有写入标记*/
for(int32_t i = 0; i < 256; i++){
LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS+(i*EACH_INDEX_SPACE),sizeof(LOG_INDEX_UNION));
if(tLogIndexUnion.IndexArry[LOG_INDEX_TOTAL] == LOG_WRITE_FLAG){
i_reord = i;
}else{
break;
}
}
/* 如果255个位置中不全是有标志的,则提前当前位置的日志索引 */
if((i_reord != 255)&&(i_reord != -1)){
LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS + (i_reord * EACH_INDEX_SPACE);
LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS + CHIPSET_SECTOR_SIZE);
return LOG_PROC_SUCCEED;
}
/* 遍历第二个块,判断每个位置是否都有写入标记*/
for(int32_t i = 256; i < 512; i++){
LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS+(i*EACH_INDEX_SPACE),sizeof(LOG_INDEX_UNION));
if(tLogIndexUnion.IndexArry[LOG_INDEX_TOTAL] == LOG_WRITE_FLAG){
i_reord = i;
}else{
break;
}
}
/* 如果255个位置中不全是有标志的,则提前当前位置的日志索引 */
if((i_reord != 511)&&(i_reord != -1)){
LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS + (i_reord * EACH_INDEX_SPACE);
LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);
return LOG_PROC_SUCCEED;
}
/* 如果两个块中都没有标记,则写入默认值 */
if(i_reord == -1){
LOG_SYS_WRITE((uint8_t*)cDefaultLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS,sizeof(LOG_INDEX_UNION));
rState = LogSysInfo_getIndex(&tLogIndexUnion);
if(rState == LOG_PROC_FAILED){
return LOG_PROC_FAILED;
}else{
memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
return LOG_PROC_SUCCEED;
}
}
/* 所有512个位置都有标记,则设定最后一个为索引存储位置 */
LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS + (511 * EACH_INDEX_SPACE);
memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_setIndex
* 功能说明: 存储日志索引
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_setIndex(LOG_INDEX_UNION uLogIndexUnion)
{
//memcpy(sLogIndexUnion.IndexArry,uLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
LOG_INDEX_ADDR = LOG_INDEX_ADDR + EACH_INDEX_SPACE;
if(LOG_INDEX_ADDR >= (LOG_SYS_INDEX_ADDRESS + LOG_SYS_INDEX_TOAL_SIZE)){
LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS;
LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);
LOG_SYS_WRITE(uLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
}else{
LOG_SYS_WRITE(uLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
}
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_getIndex
* 功能说明: 读取日志索引
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getIndex(LOG_INDEX_UNION* pLogIndexUnion)
{
LOG_SYS_READ(pLogIndexUnion->IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
if(pLogIndexUnion->IndexArry[LOG_INDEX_TOTAL] != LOG_WRITE_FLAG){
return LOG_PROC_FAILED;
}else{
return LOG_PROC_SUCCEED;
}
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_initInfo
* 功能说明: 日志系统读取掉电日志到正常日志中
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_initInfo(void)
{
LOG_INDEX_UNION tLogIndexUnion;
LOG_CONTENT_UNION tLogOutageUnion;
//1st: get the SYS_LOG_INDEX_ADDRESS page
LogSysInfo_getIndex(&tLogIndexUnion);
//2nd: get the powerdown logging
LogSysInfo_getOutage(&tLogOutageUnion);
//3rd: write the log at the syslog
if(tLogOutageUnion.ContentStruct.writeFlag == LOG_WRITE_FLAG){
LogSysInfo_recordInfo(tLogOutageUnion);
}else{
/* warnning --------------------*/
}
//4th: erase the power outage buff page
LogSysInfo_clrOutage();
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_recordInfo
* 功能说明: 记录一条日志信息,索引更新
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_recordInfo(LOG_CONTENT_UNION uLogContentUnion)
{
/*1st: According to index calculate the adress */
sLogIndexUnion.IndexStruct.cntTotal += 1;
sLogIndexUnion.IndexStruct.rawTotal = (sLogIndexUnion.IndexStruct.cntTotal >= LOG_INFO_TOTAL_CNT) ?\
LOG_INFO_TOTAL_CNT : sLogIndexUnion.IndexStruct.cntTotal;
sLogIndexUnion.IndexStruct.curIndex = (sLogIndexUnion.IndexStruct.cntTotal - 1)%\
LOG_INFO_TOTAL_CNT * EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS;
if(sLogIndexUnion.IndexStruct.curIndex >= (LOG_SYS_INFO_TOAL_SIZE + LOG_SYS_INFO_ADDRESS))
sLogIndexUnion.IndexStruct.curIndex = LOG_SYS_INFO_ADDRESS;
/* Earaze the sector , cut down the total log */
if(0 == (sLogIndexUnion.IndexStruct.curIndex % CHIPSET_SECTOR_SIZE)){
LOG_SYS_ERASE(sLogIndexUnion.IndexStruct.curIndex);
sLogIndexUnion.IndexStruct.rawTotal -= (CHIPSET_SECTOR_SIZE / EACH_LOG_SPACE);
}
/*2nd: record the log index to eeprom */
sLogIndexUnion.IndexStruct.writeFlag = LOG_WRITE_FLAG;
LogSysInfo_setIndex(sLogIndexUnion);
/*3rd: get the log number */
uLogContentUnion.ContentStruct.curNum = sLogIndexUnion.IndexStruct.cntTotal;
uLogContentUnion.ContentStruct.curTime = RTC_GetCounter(); //to update
uLogContentUnion.ContentStruct.verifyVal = LogSysInfo_calcXor8(uLogContentUnion.ConentArry,LOG_CONTENT_TOTAL);
uLogContentUnion.ContentStruct.writeFlag = LOG_WRITE_FLAG;
/*4th: record the loginfo */
LOG_SYS_WRITE(uLogContentUnion.ConentArry,sLogIndexUnion.IndexStruct.curIndex,EACH_LOG_SPACE);
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_getRecentInfo
* 功能说明: 获取最近某一条日志信息
* 形 参: pLogContentUnion:日志信息指针 recentNum: 0表示最近的日志,(0~LOG_INFO_TOTAL_CNT-1)
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getRecentInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t recentNum)
{
int32_t tSysLogAddr = 0;
/*Only more than need is ok*/
if(sLogIndexUnion.IndexStruct.cntTotal <= recentNum){
return LOG_PROC_FAILED;
}
/* Get the real index */
tSysLogAddr = ((sLogIndexUnion.IndexStruct.cntTotal - recentNum - 1) % LOG_INFO_TOTAL_CNT) *\
EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS;
/* For protect , do not reach there */
if(tSysLogAddr < LOG_SYS_INFO_ADDRESS){
tSysLogAddr = LOG_SYS_INFO_TOAL_SIZE + LOG_SYS_INFO_ADDRESS - EACH_LOG_SPACE;
}
LOG_SYS_READ(pLogContentUnion->ConentArry,tSysLogAddr,EACH_LOG_SPACE);
/* Judge the log info is right */
if(pLogContentUnion->ContentStruct.writeFlag == LOG_WRITE_FLAG)
return LOG_PROC_SUCCEED;
else
return LOG_PROC_FAILED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_getSerialInfo
* 功能说明: 获取指定序号的日志
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getSerialInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t serNum)
{
int32_t tSysLogAddr = 0x000000;
int32_t tSysLogNum = 0;
/*Only more than need is ok*/
if(serNum <= 0){
return LOG_PROC_FAILED;
}
if(sLogIndexUnion.IndexStruct.cntTotal < serNum){
return LOG_PROC_FAILED;
}
tSysLogNum = serNum % LOG_INFO_TOTAL_CNT;
tSysLogAddr = (tSysLogNum -1) * EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS;
LOG_SYS_READ(pLogContentUnion->ConentArry,tSysLogAddr,EACH_LOG_SPACE);
/* Judge the log info is right */
if(pLogContentUnion->ContentStruct.writeFlag == LOG_WRITE_FLAG)
return LOG_PROC_SUCCEED;
else
return LOG_PROC_FAILED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_clrLogOutage
* 功能说明: 清楚掉电区日志数据
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_clrOutage(void)
{
uint8_t tBytesFill[EACH_LOG_SPACE]= {0};
LOG_SYS_WRITE(tBytesFill,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_setLogOutage
* 功能说明: 存储掉电数据
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_setOutage(LOG_CONTENT_UNION uLogContentUnion)
{
LOG_SYS_WRITE(uLogContentUnion.ConentArry,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_getSerLogInfo
* 功能说明: 获取掉电数据
* 形 参: 无
* 返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getOutage(LOG_CONTENT_UNION* pLogContentUnion)
{
LOG_SYS_READ(pLogContentUnion->ConentArry,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);
return LOG_PROC_SUCCEED;
}
/*
*********************************************************************************************************
* 函 数 名: LogSysInfo_calcXor8
* 功能说明: 计算校验值
* 形 参: pVarArry:需要校验的数组 len:数据长度
* 返 回 值: 执行状态
*********************************************************************************************************
*/
uint8_t LogSysInfo_calcXor8(uint8_t *pVarArry, uint8_t len)
{
uint8_t rvalue;
rvalue = pVarArry[0];
for(uint8_t i = 1; i < len; i++){
rvalue ^= pVarArry[i];
}
return rvalue;
}