单片机日志记录系统

2019-04-15 18:13发布

单片机日志系统架构

说明: 日志记录系统按照API封装的思想只在接口文件中保留功能性程序,及 init ,set ,get;存储器使用华邦的w25q64,最低擦除的为1个sector(4096Bytes);日志系统主要分为三个部分 1、日志索引 ,2、断电日志存储区,3、日志存储区

1、日志索引:

为了避免对单个地址持续擦写造成块损坏,日志索引使用两个sector作为日志的索引存储区,日志索引每写一次地址增加16字节。当开机初始化的时候按照一定的方法将最新的索引页读取出来,用于对日志记录的地址进行记录。

2、断电日志

为了能够记录断电瞬间设备的运行情况,需要存储数据到断电日志区,等待下次开机后将断电日志记录到日志中。然后将断电日志区的数据擦除。

3、日志存储区

目前设计的是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; }