一種簡易log記錄系統設計
阿新 • • 發佈:2018-11-20
/************************************************************* * 轉載時請保留部落格連結地址:https://blog.csdn.net/yunjie167/article/details/84285513 **************************************************************/ #include <stdio.h> #include <string.h> #define u8 unsigned char #define u16 unsigned short #define u32 unsigned long #define ERROR_OPREA -1 #define ERROR_NOSPACE -2 #define ERROR_NO_UPDATE_LOG -3 #define ERROR_NO_RECORD -4 #define PAGENUMS 4 #define PAGESIZE 512 u8 VirFlashBuff[PAGENUMS][PAGESIZE]; #define ITEM_HEADER_SIZE sizeof(SFS_Item_t) typedef struct { u16 remain; //剩餘的位元組數 u16 recycle; //可回收的位元組數 } SFS_Info_t; SFS_Info_t sfs_info; #define LOGMSG_KEY 0xFE #define MAGICNUM 0xAABB #define UNUSEVALUE 0xFFFFFFFF #define MARK_USE 0xDF #define MARK_DIRTY 0xDD #define FLASHSIZE sizeof(VirFlashBuff) /* typedef struct { const SFS_Item_t *p_header; const void * p_data; } sfs_flash_record_t;*/ typedef struct { u16 magic; u8 pagenum; u8 pagetype; //u16 page_state; //u16 resv; } SFS_Header_t; SFS_Header_t SFS_Header; typedef struct { u8 recodeKEY; u8 mark; u16 length; } SFS_Item_t; /* typedef struct { u16 recodeKEY; } SFS_Des_t;*/ //flash裡建議用字來儲存,這裡只是模擬flash的操作 int my_memcpy(u32 *des,const u32 *src,int length) { int flag=0; int cpsize=0; if(((u32)src&0x03)!=0) printf("地址不對齊!!!!!!!!!!!!!!!!!!!\n"); if(length>0) { if(length & 0x03) flag=1; length>>=2; length+=flag; cpsize=length<<2; while(length--) *des++=*src++; } return cpsize; } void SFS_Init(void) { u32 *t=(u32 *)VirFlashBuff; if(*t != MAGICNUM) { memset(VirFlashBuff,0xff,sizeof(VirFlashBuff)); SFS_Header.magic=MAGICNUM; memcpy(VirFlashBuff,&SFS_Header,sizeof(SFS_Header)); sfs_info.remain=sizeof(VirFlashBuff)-sizeof(SFS_Header); sfs_info.recycle=0; printf("整個Flash快取已經初始化過了! sfs_info.remain=%ld\n",sfs_info.remain); } //如果已經初始化的了,也得計算下sfs_info.remain } u8 * Find_Record(SFS_Item_t *des) { u32 *pstart=(u32 *)(((u8 *)&VirFlashBuff)+(sizeof(SFS_Header_t))); SFS_Item_t tmpdes; for(;pstart<pstart+FLASHSIZE/4;) { if(*pstart!=UNUSEVALUE) { tmpdes=*(SFS_Item_t *)&(*pstart); if(tmpdes.recodeKEY==des->recodeKEY && tmpdes.mark!=MARK_DIRTY) { des->length=tmpdes.length; return (u8 *)(pstart+sizeof(SFS_Item_t)/4); //偏移到資料區域 } else { tmpdes=*(SFS_Item_t*)pstart; //尋找下一個資料專案 pstart+=(tmpdes.length+sizeof(SFS_Item_t))/4; if(tmpdes.length%4!=0) pstart++; } } else { return NULL; } } } u8 * Find_Record_Token(SFS_Item_t *des,u32 **ftok) { u32 *pstart; SFS_Item_t tmpdes; u8 *retaddr=NULL; if(*ftok!=NULL) { pstart=*ftok; } else { pstart=(u32 *)(((u8 *)&VirFlashBuff)+(sizeof(SFS_Header_t))); } for(;pstart<pstart+FLASHSIZE/4;) { if(*pstart!=UNUSEVALUE) { tmpdes=*(SFS_Item_t *)&(*pstart); if(tmpdes.recodeKEY==des->recodeKEY && tmpdes.mark!=MARK_DIRTY) { des->length=tmpdes.length; retaddr=(u8 *)(pstart+sizeof(SFS_Item_t)/4); tmpdes=*(SFS_Item_t*)pstart; //將下一個專案地址賦值給ftok pstart+=(tmpdes.length+sizeof(SFS_Item_t))/4; if(tmpdes.length%4!=0) pstart++; *ftok=pstart; return retaddr; } else { tmpdes=*(SFS_Item_t*)pstart; //尋找下一個資料專案 pstart+=(tmpdes.length+sizeof(SFS_Item_t))/4; if(tmpdes.length%4!=0) pstart++; } } else { *ftok=NULL; return NULL; } } } u8 *FindEmptyPostion(void) { u32 *pstart=(u32 *)(((u8 *)&VirFlashBuff)+(sizeof(SFS_Header_t))); SFS_Item_t tmpdes; for(;pstart<pstart+FLASHSIZE/4;) { if(*pstart==UNUSEVALUE) { printf("FindEmptyPostion():pstart=0x%X \n",pstart); return (u8 *)pstart; } else { tmpdes=*(SFS_Item_t*)pstart; //尋找下一個資料專案 pstart+=(tmpdes.length+sizeof(SFS_Item_t))/4; if(tmpdes.length%4!=0) pstart++; } } return NULL; } int SaveItem2Falsh(SFS_Item_t *des,void *pMsg,int length) { u8 *pstart; int cpysize; if(sfs_info.remain<length+ITEM_HEADER_SIZE) //儲存空間不足,直接返回 return -2; pstart=FindEmptyPostion(); if(pstart!=NULL) { printf("找到一個空的位置:0x%X,",pstart); des->length=length; des->mark=MARK_USE; my_memcpy((u32 *)pstart,(u32 *)des,sizeof(SFS_Item_t)); //memcpy(pstart,des,sizeof(SFS_Item_t)); //將記錄寫上 cpysize=my_memcpy((u32 *)(pstart+sizeof(SFS_Item_t)),(u32 *)pMsg,length); //memcpy(pstart+sizeof(SFS_Item_t),pMsg,length); sfs_info.remain-=(cpysize+ITEM_HEADER_SIZE); printf("剩餘%d個位元組\n",sfs_info.remain); return 0; } return -1; } int delete_record(SFS_Item_t *des) { u8 *p_header; SFS_Item_t *tmpdes; int flag=0; int ret=0; if(des->recodeKEY==LOGMSG_KEY) //如果是日誌類的要刪除就得全部刪除 { flag=1; printf("\t您刪除的是日誌類訊息,會全部刪除!!!!!!\t"); } do { if((p_header=Find_Record(des)) != NULL) { p_header-=ITEM_HEADER_SIZE; //指向頭域 tmpdes=(SFS_Item_t *)p_header; tmpdes->mark=MARK_DIRTY; sfs_info.recycle+=tmpdes->length+ITEM_HEADER_SIZE; ret++; } else break; } while(flag); return ret; } int update_a_record(SFS_Item_t *des,void *pMsg,int length) { u8 *p_header; SFS_Item_t *tmpdes; int ret=-1; if(des->recodeKEY==LOGMSG_KEY) { printf("\t日誌類資訊不支援更改!!!!!!\t"); return -3; } if(sfs_info.remain<length+ITEM_HEADER_SIZE) //儲存空間不足,直接返回 return -2; ret=delete_record(des); //刪除掉之前的舊記錄 if(ret<0) return ret; return SaveItem2Falsh(des, pMsg, length); //再將新的儲存進去 } #define TEST_KEY 0x0D #pragma pack (push,4) typedef struct { int a; u8 str[16]; float b; u8 c; short d; } TestVal_t; #pragma pack(pop) TestVal_t TestVal; int ret; int main() { int repeat; SFS_Init(); SFS_Item_t des; des.recodeKEY=TEST_KEY; strcpy(TestVal.str,"hello!"); TestVal.a=0x11223344; TestVal.b=3.1415926f; ret=SaveItem2Falsh(&des,&TestVal,sizeof(TestVal_t)); if(ret>=0) { printf("儲存資料成功1!\n"); ret=delete_record(&des); if(ret>=0) { printf("刪除記錄1成功!!!\n"); } } //------------------------------------ TestVal.a=0x33221199; TestVal.c=0x55; TestVal.d=0xaa66; ret=SaveItem2Falsh(&des,&TestVal,sizeof(TestVal_t)); if(ret>=0) { printf("儲存資料成功2!\n"); //--------------update------------------ printf("更新儲存記錄2...\n"); TestVal.a=0x44444444; if(update_a_record(&des,&TestVal,sizeof(TestVal_t))>=0) { printf("更新儲存記錄2成功!\n\n"); } } //--------------find------------------ { u8 *p_recode; TestVal_t readval; des.recodeKEY=TEST_KEY; if((p_recode=Find_Record(&des))!=NULL) { memcpy(&readval,p_recode,des.length); printf("找到一個記錄! 0x%X length=%d\n",p_recode,des.length); printf("readval.str=%s,readval.a=0x%X,readval.b=%f,readval.c=0X%x,readval.d=0X%x\n" ,readval.str,readval.a,readval.b,readval.c,readval.d); } else { printf("未找到KEY=0x%X\n",des.recodeKEY); } } //--------------save a string------------------ repeat=5; while(repeat) { int stringlen; //des.recodeID=LOGMSG_ID; des.recodeKEY=LOGMSG_KEY; char mytest_str[64];//="你們好啊今天杭州下大雪!!!!.\n"; sprintf(mytest_str,"你們好啊今天杭州下大雪! %d\n",repeat); stringlen=strlen(mytest_str); ret=SaveItem2Falsh(&des,mytest_str,stringlen+1); //加1是想多存一個字串結束符 if(ret>=0) { printf("儲存字串 %d\n",repeat); } else { printf("儲存空間不足!!!\n"); if(sfs_info.recycle+sfs_info.remain>=stringlen+1+ITEM_HEADER_SIZE) { printf("回收後的空間是足夠的.remain=%d\n",sfs_info.recycle+sfs_info.remain); } else { printf("回收後的空間還是不夠 !!!\n"); } break; } repeat--; } //--------------find all log------------------ printf("*********** find all log!!! ***********\n"); { u8 *p_recode; u32 *ftok=NULL; des.recodeKEY=LOGMSG_KEY; do { if((p_recode=Find_Record_Token(&des,&ftok))!=NULL) { printf("找到一個記錄!length=%d %.*s\n",des.length,des.length,p_recode); } else { printf("查詢結束!\n"); } } while(ftok!=NULL); } des.recodeKEY=LOGMSG_KEY; ret=delete_record(&des); printf("刪除記錄%d條\n",ret); printf("end\n"); }
一個簡易檔案日誌記錄系統,適合微控制器使用.