中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. "); //-->

        博客專欄

        EEPW首頁 > 博客 > 【嵌入式SD NAND】基于FATFS/Littlefs文件系統(tǒng)的日志框架實(shí)現(xiàn)

        【嵌入式SD NAND】基于FATFS/Littlefs文件系統(tǒng)的日志框架實(shí)現(xiàn)

        發(fā)布人:13537608950 時(shí)間:2024-03-13 來源:工程師 發(fā)布文章
        文章目錄

        【嵌入式】基于FATFS/Littlefs文件系統(tǒng)的日志框架實(shí)現(xiàn)

        1. 概述

        2. 設(shè)計(jì)概要

        3. 設(shè)計(jì)實(shí)現(xiàn)

        3.1 初始化 `init`

        3.2 日志寫入 `write`

        3.3 日志讀取 `read`

        3.4 注銷 `deinit`

        3.5 全部代碼匯總

        4. 測(cè)試

        5. 總結(jié)


        1. 概述

        那么在移植好了文件系統(tǒng)之后,我們又應(yīng)該如何應(yīng)用文件系統(tǒng)呢?


        很多人會(huì)說,這個(gè)簡(jiǎn)單,就操作文件嘛!open、read、write、close不就行了嗎!當(dāng)然對(duì)于簡(jiǎn)單的使用,掌握open、read、write、close,去存儲(chǔ)一兩個(gè)文件或者從一兩個(gè)文件中簡(jiǎn)單的讀取下數(shù)據(jù)這確實(shí)沒有什么難度。但在實(shí)際應(yīng)用中,特別是產(chǎn)品開發(fā)過程中,往往不只是簡(jiǎn)單的操作一兩個(gè)文件就可以的,如果真是這樣,那費(fèi)那么大勁移植文件系統(tǒng)多少有點(diǎn)浪費(fèi)!


        在實(shí)際項(xiàng)目開發(fā)中,往往需要依托文件系統(tǒng)操作諸多的文件,操作諸多的數(shù)據(jù)。如通過配置文件配置機(jī)器設(shè)備信息、通過升級(jí)文件進(jìn)行產(chǎn)品升級(jí)、通過存放字庫文件實(shí)現(xiàn)多語言支持等等,這些都是比較簡(jiǎn)單的操作,讀寫不是很頻繁,相對(duì)來說實(shí)現(xiàn)比較簡(jiǎn)單,還有一類需求讀寫會(huì)相當(dāng)頻繁,且大多數(shù)產(chǎn)品內(nèi)都希望存在的,那便是日志文件,通過日志文件來記錄設(shè)備的運(yùn)行數(shù)據(jù)。日志文件不同于其他功能,其往往需要具備幾個(gè)基本特性需求:


        • 單個(gè)文件大小限制

        • 日志總大小空間占用限制

        • 自動(dòng)循環(huán)覆蓋


        網(wǎng)上也有一些開源的日志框架,如 Log4j,不過大都是基于 java / c ++ 實(shí)現(xiàn)的,雖然功能比較全面,但比較繁雜,且也難以移植應(yīng)用于嵌入式開發(fā)中。而在嵌入式開發(fā)中,可能也受限于資源限制,并沒有發(fā)現(xiàn)不錯(cuò)的基于文件系統(tǒng)的開源日志框架(至少博主目前沒有發(fā)現(xiàn),有的話歡迎大家評(píng)論區(qū)討論 ),對(duì)于如何實(shí)現(xiàn)一個(gè)日志框架很多人一下子可能沒有頭緒,綜上,本文將分享一個(gè)簡(jiǎn)單的基于文件系統(tǒng)的日志程序以供大家思考。

        2. 設(shè)計(jì)概要

        我們需要實(shí)現(xiàn)的日志模塊的核心需求為:


        • 單個(gè)文件大小限制

        • 日志總大小空間占用限制

        • 自動(dòng)循環(huán)覆蓋

        對(duì)于一個(gè)模塊,對(duì)外僅需提供其操作的接口即可,內(nèi)部的算法實(shí)現(xiàn)均無需對(duì)外開放,而對(duì)于此日志模塊,對(duì)外只需提供基本的以下四個(gè)接口即可:


        • 初始化 init

        • 寫日志 write

        • 讀日志 read

        • 注銷 deinit

        關(guān)于日志存儲(chǔ)的核心思想如下:


        寫數(shù)據(jù)之前先判斷當(dāng)前操作的文件是否超出單個(gè)文件大小限制,如超出大小限制則進(jìn)行日志輪轉(zhuǎn),創(chuàng)建一個(gè)新的日志文件并判斷日志文件總大小是否超出限制,如果超出則刪除最早的那一份日志文件


        關(guān)于日志存儲(chǔ)的詳細(xì)設(shè)計(jì)如下:


        日志文件格式采用:<filename>.log ,當(dāng)當(dāng)前文件達(dá)到單個(gè)文件大小之后,進(jìn)行文件輪轉(zhuǎn);


        假定當(dāng)前限制日志每個(gè)日志文件大小為2048Byte,最多存儲(chǔ)10個(gè)文件;


        當(dāng)當(dāng)前文件達(dá)到單個(gè)文件大小之后,迭代修改日志文件名:


        • <filename>.log -> <filename>.log.0

        • <filename>.log.0 -> <filename>.log.1

        • <filename>.log.1 -> <filename>.log.2

        • <filename>.log.8 -> <filename>.log.9

        • 刪除 <filename>.log.9

        ps:注意實(shí)際代碼操作的時(shí)候,文件修改順序是反過來的,也就是先 刪除 <filename>.log.9 再將<filename>.log.8 -> <filename>.log.9

        3. 設(shè)計(jì)實(shí)現(xiàn)3.1 初始化 init

        初始化部分代碼主要功能是完成日志數(shù)據(jù)結(jié)構(gòu)體的構(gòu)造,并通過傳入?yún)?shù) log_file_cfg_t cfg 配置日志文件的配置信息,如單個(gè)日志文件大小、日志文件名、最多存放的日志文件數(shù)等內(nèi)容,日志模塊初始化部分代碼如下:

        1. log_file_t log_storage_init(log_file_cfg_t cfg)

        2. {

        3.     log_file_t log = NULL;

        4.     log_file_cfg_t log_cfg = NULL;

        5.     log_file_read_t log_read = NULL;


        6.     log = (log_file_t)malloc(sizeof(struct log_file_config));

        7.     if (log == NULL)

        8.         goto error;

        9.     

        10.     log_cfg = (log_file_cfg_t)malloc(sizeof(struct log_file_config));

        11.     if (log_cfg == NULL) {

        12.         free(log);

        13.         log = NULL;

        14.         goto error;

        15.     }


        16.     log_read = (log_file_read_t)malloc(sizeof(struct log_file_read));

        17.     if (log_read == NULL) {

        18.         free(log);

        19.         log = NULL;

        20.         free(log_cfg);

        21.         log_cfg = NULL;

        22.         goto error;

        23.     }


        24.     memcpy(log_cfg, cfg, sizeof(struct log_file_config));

        25.     log_read->rotate_index = 0;

        26.     log_read->file_offset = 0;

        27.     

        28.     log->cfg = log_cfg;

        29.     log->read = log_read;

        30.     log->user_data = NULL;


        31. error:

        32.     return log;

        33. }

        3.2 日志寫入 write

        日志寫入部分代碼主要分為兩大部分,一部分是正常寫入,另一部分是文件輪轉(zhuǎn);當(dāng)寫入的文件超過單個(gè)文件大小限制時(shí),即會(huì)觸發(fā)文件輪轉(zhuǎn)操作。


        在文件輪轉(zhuǎn)中,主要做的是:創(chuàng)建一個(gè)新的日志文件并判斷日志文件總大小是否超出限制,如果超出則刪除最早的那一份日志文件,具體設(shè)計(jì)細(xì)節(jié)可參考上文設(shè)計(jì)概要中的詳細(xì)設(shè)計(jì)部分。


        實(shí)現(xiàn)代碼如下:

        1. static int log_rotate(log_file_t log)

        2. {

        3.     int ret = 0;

        4.     FILE *fp;

        5.     char old_filename[NAME_MAX + 10] = {0};

        6.     char new_filename[NAME_MAX + 10] = {0};


        7.     for (int i = log->cfg->rotate_num; i > 0; i --) {

        8.         memset(old_filename, 0, sizeof(old_filename));

        9.         memset(new_filename, 0, sizeof(new_filename));


        10.         snprintf(old_filename, sizeof(old_filename), i ? "%s_%d.log" : "%s.log", log->cfg->filename, i - 1);

        11.         snprintf(new_filename, sizeof(new_filename), "%s_%d.log", log->cfg->filename, i);


        12.         printf("old:%s new:%s\n", old_filename, new_filename);

        13.         

        14.         if ((fp = fopen(new_filename, "r")) != NULL) {

        15.             if (fclose(fp) != 0) {

        16.                 ret = -1;

        17.                 goto error;

        18.             }

        19.             if (remove(new_filename) != 0) {

        20.                 ret = -2;

        21.                 goto error;

        22.             }

        23.         }


        24.         if ((fp = fopen(old_filename, "r")) != NULL) {

        25.             if (fclose(fp) != 0) {

        26.                 ret = -1;

        27.                 goto error;

        28.             }

        29.             if (rename(old_filename, new_filename) != 0) {

        30.                 ret = -3;

        31.                 goto error;

        32.             }

        33.         }

        34.     }


        35. error:

        36.     return ret;

        37. }


        38. int log_storage_write(log_file_t log, const unsigned char *buf, unsigned int len)

        39. {

        40.     int ret = 0;

        41.     int file_size = 0;

        42.     char full_filename[NAME_MAX + 5] = {0};

        43.     FILE *fp = NULL;


        44.     if (log == NULL || log->cfg == NULL || log->read == NULL || buf == NULL || len == 0) {

        45.         ret = -1;

        46.         goto param_error;

        47.     }


        48.     snprintf(full_filename, sizeof(full_filename), "%s.log", log->cfg->filename);

        49.     

        50.     printf("fullfilename:%s\n", full_filename);

        51.     log_file_lock();


        52.     fp = fopen(full_filename, "a+b");

        53.     if (fp == NULL) {

        54.         ret = -2;

        55.         goto error;

        56.     }


        57.     fseek(fp, 0L, SEEK_END);

        58.     file_size = ftell(fp);

        59.     printf("file_size:%d\n", file_size);

        60.     if ((file_size + len) > log->cfg->max_size) {

        61.         if (fclose(fp) != 0) {

        62.             ret = -3;

        63.             goto error;

        64.         }


        65.         int j = 0;

        66.         j = log_rotate(log);

        67.         printf("log rotate:%d\n", j);

        68.         fp = fopen(full_filename, "a+b");

        69.         if (fp == NULL) {

        70.             ret = -2;

        71.             goto error;

        72.         }

        73.     }


        74.     if (fwrite(buf, len, 1, fp) != 1) {

        75.         fclose(fp);

        76.         ret = -4;

        77.         goto error;

        78.     }


        79. error:

        80. if (fp != NULL) {

        81. if (fclose(fp) != 0) {

        82. ret = -3;

        83. goto error;

        84. }

        85. }

        86.     log_file_unlock();

        87. param_error:

        88.     return ret;

        89. }

        3.3 日志讀取 read

        此處日志讀取在本文主題中非重點(diǎn)設(shè)計(jì)內(nèi)容,因此此處做簡(jiǎn)單設(shè)計(jì),通過傳入?yún)?shù)判斷應(yīng)該讀取哪一份文件之后進(jìn)行直接讀取。設(shè)計(jì)代碼如下:

        1. int log_storage_read(log_file_t log, unsigned int rotate_num, unsigned char *buf, unsigned int *len)

        2. {

        3.     int ret = 0;

        4.     int file_size = 0;

        5.     char full_filename[NAME_MAX + 5] = {0};

        6.     FILE *fp = NULL;


        7.     if (log == NULL || log->cfg == NULL || log->read == NULL || buf == NULL || len == 0) {

        8.         ret = -1;

        9.         goto param_error;

        10.     }


        11.     if (rotate_num == 0)

        12.         snprintf(full_filename, sizeof(full_filename), "%s.log", log->cfg->filename);

        13.     else

        14.         snprintf(full_filename, sizeof(full_filename), "%s.log.%d", log->cfg->filename, rotate_num);


        15.     log_file_lock();


        16.     fp = fopen(full_filename, "a+b");

        17.     if (fp == NULL) {

        18.         ret = -2;

        19.         goto error;

        20.     }

        21.     /* check file length. */

        22.     fseek(fp, 0L, SEEK_END);

        23.     file_size = ftell(fp);

        24.     printf("file_size:%d\n", file_size);

        25.     if (file_size < *len)

        26.         *len = file_size;


        27.     fseek(fp, 0L, SEEK_SET);

        28.     if (fread(buf, *len, 1, fp) != 1) {

        29.         ret = -3;

        30.         fclose(fp);

        31.         goto error;

        32.     }


        33. error:

        34. if (fp != NULL) {

        35. if (fclose(fp) != 0) {

        36. ret = -4;

        37. goto error;

        38. }

        39. }

        40.     log_file_unlock();

        41. param_error:

        42.     return ret;

        43. }

        3.4 注銷 deinit

        注銷的主要功能是將我們?cè)?nbsp;init 時(shí)創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)進(jìn)行回收,如果模塊內(nèi)部有功能處于打開裝填,也應(yīng)關(guān)閉模塊的功能,此處我們僅需對(duì) init 時(shí)創(chuàng)建的 log_file_t log 數(shù)據(jù)結(jié)構(gòu)體進(jìn)行注銷、內(nèi)存回收即可,具體代碼實(shí)現(xiàn)如下:

        1. int log_storage_deinit(log_file_t log)

        2. {

        3. if (log == NULL)

        4. return -1;

        5. if (log->cfg != NULL)

        6. free(log->cfg);

        7. if (log->read != NULL)

        8. free(log->read);

        9. if (log->user_data != NULL)

        10. free(log->user_data);

        11. free(log);

        12. return 0;

        13. }

        3.5 全部代碼匯總

        日志模塊內(nèi)核頭文件:simple_storage.h

        1. #ifndef __SIMPLE_STORAGE_H__

        2. #define __SIMPLE_STORAGE_H__


        3. #define NAME_MAX        40


        4. struct log_file_config {

        5.     const char filename[NAME_MAX];     /* Filename of this type. */

        6.     int max_size;       /* single file max size. */

        7.     int rotate_num;     /* The number of files that support rotate. */

        8. };

        9. typedef struct log_file_config* log_file_cfg_t;


        10. struct log_file_read {

        11.     int rotate_index;   /* The rotate file index. */

        12.     int file_offset;    /* The offset of the currently read file. */

        13. };

        14. typedef struct log_file_read* log_file_read_t;


        15. struct log_file {

        16.     log_file_cfg_t cfg;

        17.     log_file_read_t read;

        18.     void *user_data;

        19. };

        20. typedef struct log_file* log_file_t;



        21. log_file_t log_storage_init(log_file_cfg_t cfg);

        22. int log_storage_write(log_file_t log, const unsigned char *buf, unsigned int len);

        23. int log_storage_read(log_file_t log, unsigned int rotate_num, unsigned char *buf, unsigned int *len);

        24. int log_storage_deinit(log_file_t log);



        25. #endif /* __SIMPLE_STORAGE_H__ */


        日志模塊內(nèi)核文件: simple_storage.c

        1. #include "simple_storage.h"

        2. #include "simple_storage_port.h"

        3. #include <stdio.h>

        4. #include <string.h>


        5. log_file_t log_storage_init(log_file_cfg_t cfg)

        6. {

        7.     log_file_t log = NULL;

        8.     log_file_cfg_t log_cfg = NULL;

        9.     log_file_read_t log_read = NULL;


        10.     log = (log_file_t)malloc(sizeof(struct log_file_config));

        11.     if (log == NULL)

        12.         goto error;

        13.     

        14.     log_cfg = (log_file_cfg_t)malloc(sizeof(struct log_file_config));

        15.     if (log_cfg == NULL) {

        16.         free(log);

        17.         log = NULL;

        18.         goto error;

        19.     }


        20.     log_read = (log_file_read_t)malloc(sizeof(struct log_file_read));

        21.     if (log_read == NULL) {

        22.         free(log);

        23.         log = NULL;

        24.         free(log_cfg);

        25.         log_cfg = NULL;

        26.         goto error;

        27.     }


        28.     memcpy(log_cfg, cfg, sizeof(struct log_file_config));

        29.     log_read->rotate_index = 0;

        30.     log_read->file_offset = 0;

        31.     

        32.     log->cfg = log_cfg;

        33.     log->read = log_read;

        34.     log->user_data = NULL;


        35. error:

        36.     return log;

        37. }


        38. static int log_rotate(log_file_t log)

        39. {

        40.     int ret = 0;

        41.     FILE *fp;

        42.     char old_filename[NAME_MAX + 10] = {0};

        43.     char new_filename[NAME_MAX + 10] = {0};


        44.     for (int i = log->cfg->rotate_num; i > 0; i --) {

        45.         memset(old_filename, 0, sizeof(old_filename));

        46.         memset(new_filename, 0, sizeof(new_filename));


        47.         snprintf(old_filename, sizeof(old_filename), i ? "%s_%d.log" : "%s.log", log->cfg->filename, i - 1);

        48.         snprintf(new_filename, sizeof(new_filename), "%s_%d.log", log->cfg->filename, i);


        49.         printf("old:%s new:%s\n", old_filename, new_filename);

        50.         

        51.         if ((fp = fopen(new_filename, "r")) != NULL) {

        52.             if (fclose(fp) != 0) {

        53.                 ret = -1;

        54.                 goto error;

        55.             }

        56.             if (remove(new_filename) != 0) {

        57.                 ret = -2;

        58.                 goto error;

        59.             }

        60.         }


        61.         if ((fp = fopen(old_filename, "r")) != NULL) {

        62.             if (fclose(fp) != 0) {

        63.                 ret = -1;

        64.                 goto error;

        65.             }

        66.             if (rename(old_filename, new_filename) != 0) {

        67.                 ret = -3;

        68.                 goto error;

        69.             }

        70.         }

        71.     }


        72. error:

        73.     return ret;

        74. }


        75. int log_storage_write(log_file_t log, const unsigned char *buf, unsigned int len)

        76. {

        77.     int ret = 0;

        78.     int file_size = 0;

        79.     char full_filename[NAME_MAX + 5] = {0};

        80.     FILE *fp = NULL;


        81.     if (log == NULL || log->cfg == NULL || log->read == NULL || buf == NULL || len == 0) {

        82.         ret = -1;

        83.         goto param_error;

        84.     }


        85.     snprintf(full_filename, sizeof(full_filename), "%s.log", log->cfg->filename);

        86.     

        87.     printf("fullfilename:%s\n", full_filename);

        88.     log_file_lock();


        89.     fp = fopen(full_filename, "a+b");

        90.     if (fp == NULL) {

        91.         ret = -2;

        92.         goto error;

        93.     }


        94.     fseek(fp, 0L, SEEK_END);

        95.     file_size = ftell(fp);

        96.     printf("file_size:%d\n", file_size);

        97.     if ((file_size + len) > log->cfg->max_size) {

        98.         if (fclose(fp) != 0) {

        99.             ret = -3;

        100.             goto error;

        101.         }


        102.         int j = 0;

        103.         j = log_rotate(log);

        104.         printf("log rotate:%d\n", j);

        105.         fp = fopen(full_filename, "a+b");

        106.         if (fp == NULL) {

        107.             ret = -2;

        108.             goto error;

        109.         }

        110.     }


        111.     if (fwrite(buf, len, 1, fp) != 1) {

        112.         fclose(fp);

        113.         ret = -4;

        114.         goto error;

        115.     }


        116. error:

        117. if (fp != NULL) {

        118. if (fclose(fp) != 0) {

        119. //TODO: check the amount of disk space, delete if there is not enough space.

        120. ret = -3;

        121. goto error;

        122. }

        123. }

        124.     log_file_unlock();

        125. param_error:

        126.     return ret;

        127. }


        128. int log_storage_read(log_file_t log, unsigned int rotate_num, unsigned char *buf, unsigned int *len)

        129. {

        130.     int ret = 0;

        131.     int file_size = 0;

        132.     char full_filename[NAME_MAX + 5] = {0};

        133.     FILE *fp = NULL;


        134.     if (log == NULL || log->cfg == NULL || log->read == NULL || buf == NULL || len == 0) {

        135.         ret = -1;

        136.         goto param_error;

        137.     }


        138.     if (rotate_num == 0)

        139.         snprintf(full_filename, sizeof(full_filename), "%s.log", log->cfg->filename);

        140.     else

        141.         snprintf(full_filename, sizeof(full_filename), "%s.log.%d", log->cfg->filename, rotate_num);


        142.     log_file_lock();


        143.     fp = fopen(full_filename, "a+b");

        144.     if (fp == NULL) {

        145.         ret = -2;

        146.         goto error;

        147.     }

        148.     /* check file length. */

        149.     fseek(fp, 0L, SEEK_END);

        150.     file_size = ftell(fp);

        151.     printf("file_size:%d\n", file_size);

        152.     if (file_size < *len)

        153.         *len = file_size;


        154.     fseek(fp, 0L, SEEK_SET);

        155.     if (fread(buf, *len, 1, fp) != 1) {

        156.         ret = -3;

        157.         fclose(fp);

        158.         goto error;

        159.     }


        160. error:

        161. if (fp != NULL) {

        162. if (fclose(fp) != 0) {

        163. ret = -4;

        164. goto error;

        165. }

        166. }

        167.     log_file_unlock();

        168. param_error:

        169.     return ret;

        170. }


        171. int log_storage_deinit(log_file_t log)

        172. {

        173. if (log == NULL)

        174. return -1;

        175. if (log->cfg != NULL)

        176. free(log->cfg);

        177. if (log->read != NULL)

        178. free(log->read);

        179. if (log->user_data != NULL)

        180. free(log->user_data);

        181. free(log);

        182. return 0;

        183. }


        在日志模塊源文件的代碼中,我們可以看到實(shí)際每次操作文件的時(shí)候,都有調(diào)用一個(gè)函數(shù)鎖操作,考慮到不同平臺(tái)的鎖操作實(shí)現(xiàn)不一樣,因此將此部分通過函數(shù)導(dǎo)出來,放置在模塊的端口文件中。不同的平臺(tái)、系統(tǒng)根據(jù)各自的平臺(tái)和系統(tǒng)的情況進(jìn)行實(shí)現(xiàn),如像裸機(jī)編程這類不需要進(jìn)行鎖操作的不進(jìn)行函數(shù)實(shí)現(xiàn)即可。


        日志模塊端口頭文件:simple_storage_port.c

        1. #ifndef __SIMPLE_STORAGE_PORT_H__

        2. #define __SIMPLE_STORAGE_PORT_H__


        3. int log_file_init(void);

        4. int log_file_lock(void);

        5. int log_file_unlock(void);



        6. #endif /* __SIMPLE_STORAGE_PORT_H__ */


        日志模塊端口源文件:simple_storage_port.h

        1. #include "simple_storage_port.h"


        2. int log_file_init(void)

        3. {

        4.     return 0;

        5. }


        6. int log_file_lock(void)

        7. {

        8.     return 0;

        9. }


        10. int log_file_unlock(void)

        11. {

        12.     return 0;

        13. }

        4. 測(cè)試

        將以上代碼進(jìn)行運(yùn)行測(cè)試,硬件平臺(tái)如下:


        • 控制器: stm32f103vet6,野火指南者開發(fā)板


        • 存儲(chǔ)芯片: CS創(chuàng)世 SD nand,型號(hào):CSNP4GCR01-AMW


        • 文件系統(tǒng): FATFS,注意此日志不受文件系統(tǒng)限制


        • 操作系統(tǒng): RT-Thread,此模塊與操作系統(tǒng)無關(guān),此處只是方便使用故自行移植了rtthread

        【嵌入式SD NAND】基于FATFS/Littlefs文件系統(tǒng)的日志框架實(shí)現(xiàn)

        應(yīng)用層代碼如下:


        1. int main(void)

        2. {

        3. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

        4. HAL_Init();

        5. /* USER CODE BEGIN Init */

        6. /* USER CODE END Init */

        7. /* Configure the system clock */

        8. SystemClock_Config();

        9. /* USER CODE BEGIN SysInit */

        10. /* USER CODE END SysInit */

        11. /* Initialize all configured peripherals */

        12. MX_GPIO_Init();

        13. MX_SDIO_SD_Init();

        14. MX_USART1_UART_Init();

        15. MX_FATFS_Init();

        16. /* USER CODE BEGIN 2 */

        17. struct log_file_config log_cfg = {

        18. .filename = "test",

        19. .max_size = 2048,

        20. .rotate_num = 10,

        21. };

        22. log_file_t log = NULL;

        23. log = log_storage_init(&log_cfg);

        24. if (log == NULL)

        25. return;

        26. /* USER CODE END 2 */

        27. /* Infinite loop */

        28. /* USER CODE BEGIN WHILE */

        29. unsigned char buf[2048] = {0};

        30. int len = 0;

        31. while (1) {

        32. // ... 省略用戶代碼

        33. /* 寫入測(cè)試 */

        34. for (int i = 0; i < 2048; i++) {

        35. log_storage_write(log, "hello world", sizeof("hello world"));

        36. rt_thread_mdelay(100);

        37. }

        38. /* 讀取測(cè)試 */

        39. len = sizeof(buf);

        40. memset(buf, 0, sizeof(buf));

        41. log_storage_read(log, 1, buf, &len);

        42. for (int i = 0; i < len; i ++)

        43. rt_kprintf("%c", buf[i]);

        44. rt_thread_mdelay(1000);

        45. }

        46. }


        測(cè)試結(jié)果如下:

        1. msg> hello worldhello world hello world hello world hello world hello world hello world hello world hello world ...省略


        2. msh > ls

        3. test.log    2046

        4. test.log.0     2046

        5. test.log.1     2046

        6. test.log.2     2046

        7. test.log.3     2046

        8. test.log.4     2046

        5. 總結(jié)

        綜上便是基于文件系統(tǒng)的簡(jiǎn)易日志模塊設(shè)計(jì)的全部?jī)?nèi)容了,雖然簡(jiǎn)陋了點(diǎn),但相信對(duì)于大部分沒有接觸過日志系統(tǒng)設(shè)計(jì)的人來說提供了很好的一條設(shè)計(jì)思路。


        也正因?yàn)楹?jiǎn)易,給大家對(duì)于日志系統(tǒng)設(shè)計(jì)的優(yōu)化留足了大量的優(yōu)化空間。比如:


        文件輪轉(zhuǎn)的時(shí)候需要對(duì)每個(gè)文件的文件名進(jìn)行修改,是否可以有更好的方式不用每個(gè)文件都修改呢?

        文件名的設(shè)計(jì)是不方便閱讀的,是否可以引入時(shí)間參數(shù)?

        文件名設(shè)計(jì)如何引入了時(shí)間參數(shù),當(dāng)設(shè)備RTC備用電池掉電的時(shí)候又如何保證文件不會(huì)被錯(cuò)誤覆蓋?

        文件的讀取顯然優(yōu)化空間更大,實(shí)際上用戶不應(yīng)該傳入rotate_num 參數(shù),因?yàn)檫@是模塊內(nèi)部的參數(shù),用戶不可感知的

        文件讀取如何做到分多次讀取一個(gè)文件的內(nèi)容,且不會(huì)重復(fù),是順序讀???

        等等,以上只是我簡(jiǎn)單想到的幾點(diǎn)內(nèi)容,大家不妨思考下如何實(shí)現(xiàn)方案更好呢?當(dāng)然又還有哪些需求是需要引入的呢,也歡迎大家在評(píng)論區(qū)留言,關(guān)注我,后續(xù)抽時(shí)間再分享下改良版日志系統(tǒng)?。。?/p>


        *博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。




        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉