/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * *

© Copyright (c) 2019 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ #include "main.h" #if USE_LFS_RECORD /* Includes ------------------------------------------------------------------*/ #include #include #include #include #include "dev_spi_sdcard.h" #include "func_spi_w25qxx.h" #include "mid_littlefs_flash.h" #include "func_queue_record.h" #include "Data_deal.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ #define MAX_FILE_COUNT 20 #define NUM_FILE_SET 10 /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ const char FILE_START[] = "20"; const char FILE_END[] = ".TXT"; const char FILE_FOLD[] = "JLRECORD";//"";// /* Private function prototypes -----------------------------------------------*/ #pragma pack(4) /*4字节对齐*/ typedef struct fs_record_struct { int8_t fs_stat; const char *fold; //操作路径 int8_t * path[32]; //操作路径 int8_t name_new[32]; //最新的文件名 int8_t name_send[32]; //最老的文件名 lfs_file_t opt_file; //当前操作的文件 lfs_dir_t dir; //操作的文件名 uint32_t opt_len; uint32_t items_num; int8_t read_buf[512]; uint32_t read_len; int8_t write_buf[512]; uint32_t write_len; uint32_t file_num; int8_t file_list[MAX_FILE_COUNT][32];//保存文件名 int8_t link_ok; uint32_t free_size; }fs_record_OBJ; fs_record_OBJ fs_record_obj = { .fs_stat = true, .fold = FILE_FOLD, .items_num= 0, .file_num = 0, .link_ok = false, }; #pragma pack()/*还原默认对齐*/ void func_record_lfs_Get_Capacity(void); void func_record_lfs_files_update(char * path); void func_record_lfs_dir_qsort(size_t fcount); extern SDateTime m_datetime; /* Private user code ---------------------------------------------------------*/ uint8_t func_record_lfs_stat_get(void) { return fs_record_obj.fs_stat; } uint8_t func_record_lfs_stat_set(uint8_t stat) { fs_record_obj.fs_stat = stat; return fs_record_obj.fs_stat; } void func_record_lfs_mk_fileName(char *buf) { //fs_record_obj.path[12] = 0; #if 0 sprintf(buf,"%s/%04d%02d%02d.TXT",fs_record_obj.fold, m_datetime.year%100 + 2000, m_datetime.month%100, m_datetime.day%100 ); #elif 0 sprintf(buf,"%s/%04d%02d%02d.TXT",fs_record_obj.fold, m_datetime.day%100 + 2000, m_datetime.hour%100, m_datetime.min%100 ); #else sprintf(buf,"%s/%04d%02d%02d.TXT",fs_record_obj.fold, m_datetime.hour%100 + 2000, m_datetime.min%100, m_datetime.sec%100 ); #endif return; } /** * @brief 指定长度len,buf内容写入文件 * @retval int */ uint32_t func_record_lfs_write(void *buf ,uint32_t len) { lfs_soff_t res; UINT write_len = 0; //根据日期生成文件名,用于文件写入 func_record_lfs_mk_fileName((char *)fs_record_obj.name_new); //打开当前存在的文件; res = lfs_file_open_static(&lfs_flash, &fs_record_obj.opt_file,(char *)fs_record_obj.name_new , LFS_O_WRONLY); if(LFS_ERR_OK != res) { //检查文件个数是否超限 func_record_lfs_files_update((char *)fs_record_obj.fold); if(LFS_ERR_NOENT == res) { //创建文件并写入 res = lfs_file_open_static(&lfs_flash, &fs_record_obj.opt_file, (char*)fs_record_obj.name_new, LFS_O_RDWR| LFS_O_CREAT); if(LFS_ERR_OK != res) { fs_record_obj.fs_stat = false; return 0; } } else { return 0; } } //将当前发送文件更新为当前写入文件 strcpy((char *)fs_record_obj.name_send,(char *)fs_record_obj.name_new); fs_record_obj.opt_len = lfs_file_size(&lfs_flash, &fs_record_obj.opt_file); //操作指针移动到文件末尾 res = lfs_file_seek(&lfs_flash, &fs_record_obj.opt_file, fs_record_obj.opt_len,LFS_SEEK_END); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_file_write(&lfs_flash, &fs_record_obj.opt_file, buf, len); //lfs_file_sync(&lfs_flash, &fs_record_obj.opt_file); res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); //关闭文件 taskEXIT_CRITICAL(); /* 临界保护关闭 */ return write_len; } void func_record_lfs_get_NameSend(void) { //发送文件是否存在 if(strlen((char*)fs_record_obj.name_send) > 0) { return; } //检查文件个数是否超限 func_record_lfs_files_update((char *)fs_record_obj.fold); } /** * @brief The application entry point. * @retval int */ uint32_t func_record_lfs_read(uint8_t *buf, uint32_t len) { lfs_soff_t res; //uint32_t file_len = 0; uint32_t read_len = 0; func_record_lfs_get_NameSend(); if(strlen((char *)fs_record_obj.name_send) <= 0) { return 0; } res = lfs_file_open_static(&lfs_flash, &fs_record_obj.opt_file, (char*)fs_record_obj.name_send, LFS_O_RDONLY); if(LFS_ERR_OK != res) { return 0; } fs_record_obj.opt_len = lfs_file_size(&lfs_flash, &fs_record_obj.opt_file); //如果文件小于数据长度,则删除文件 if(fs_record_obj.opt_len < len) { res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_remove(&lfs_flash, (char*)fs_record_obj.name_send); taskEXIT_CRITICAL(); /* 临界保护关闭 */ if(res == LFS_ERR_OK) { memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); } return 0; }; res = lfs_file_seek(&lfs_flash, &fs_record_obj.opt_file, 0 - len, LFS_SEEK_END); res = lfs_file_read(&lfs_flash, &fs_record_obj.opt_file, buf, len); res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); return read_len; } int32_t func_record_lfs_remove(void *buf, uint32_t len) { lfs_soff_t res; uint32_t read_len = 0; func_record_lfs_get_NameSend(); if(strlen((char *)fs_record_obj.name_send) <= 0) { return 0; } res = lfs_file_open_static(&lfs_flash, &fs_record_obj.opt_file, (char*)fs_record_obj.name_send, LFS_O_RDWR); if(LFS_ERR_OK != res) { memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); return 0; } fs_record_obj.opt_len = lfs_file_size(&lfs_flash, &fs_record_obj.opt_file); //如果文件小于数据长度,则删除文件 if(fs_record_obj.opt_len < len) { res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_remove(&lfs_flash, (char*)fs_record_obj.name_send); taskEXIT_CRITICAL(); /* 临界保护关闭 */ if(res == LFS_ERR_OK) { memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); } return 0; }; res = lfs_file_seek(&lfs_flash, &fs_record_obj.opt_file, 0 - len, LFS_SEEK_END); res = lfs_file_read(&lfs_flash, &fs_record_obj.opt_file, buf, len); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_file_truncate(&lfs_flash, &fs_record_obj.opt_file ,fs_record_obj.opt_len - len); //截断后面的文件 res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); taskEXIT_CRITICAL(); /* 临界保护关闭 */ return read_len; } int32_t func_record_lfs_delete(uint8_t *buf,uint32_t len) { lfs_soff_t res; if(strlen((char *)fs_record_obj.name_send) <= 0) { return 0; } //打开文件 res = lfs_file_open_static(&lfs_flash, &fs_record_obj.opt_file, (char*)fs_record_obj.name_send, LFS_O_WRONLY | LFS_O_EXCL ); if ( res != LFS_ERR_OK ) { if(res == FR_NO_FILE ) { memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); memset((char*)fs_record_obj.name_new, 0x00,sizeof(fs_record_obj.name_new)); } return res; } fs_record_obj.opt_len = lfs_file_size(&lfs_flash, &fs_record_obj.opt_file); //如果文件小于数据长度,则删除文件 if(fs_record_obj.opt_len <= len) { res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_remove(&lfs_flash, (char*)fs_record_obj.name_send); taskEXIT_CRITICAL(); /* 临界保护关闭 */ if(res == LFS_ERR_OK) { memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); } return 0; }; taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_file_truncate(&lfs_flash, &fs_record_obj.opt_file, fs_record_obj.opt_len - len); //截断后面的文件 taskEXIT_CRITICAL(); /* 临界保护关闭 */ res = lfs_file_close(&lfs_flash, &fs_record_obj.opt_file); return res; } /** * 文件信息获取 */ lfs_soff_t func_record_lfs_file_check(void) { lfs_soff_t res; /* 文件操作结果 */ struct lfs_info finfo; /* 获取文件信息 */ res=lfs_stat(&lfs_flash,"TestDir/testdir.txt",&finfo); if(res==LFS_ERR_OK) { printf("“testdir.txt”文件信息:\n"); printf("》文件大小: %ld(字节)\n", finfo.size); //printf("》时间戳: %u/%02u/%02u, %02u:%02u\n", // (finfo.fdate >> 9) + 1980, finfo.fdate >> 5 & 15, finfo.fdate & 31,finfo.ftime >> 11, finfo.ftime >> 5 & 63); printf("》属性: %c%c%\n\n", (finfo.type & LFS_TYPE_DIR) ? 'D' : '-', // 是一个目录 (finfo.type & LFS_TYPE_REG) ? 'R' : '-' // 只读文件 ); } return res; } /** * @brief scan_files 递归扫描FatFs内的文件 * @param path:初始扫描路径 * @retval result:文件系统的返回值 */ lfs_soff_t func_record_lfs_scan_files (char* path) { lfs_soff_t res; //部分在递归过程被修改的变量,不用全局变量 struct lfs_info fno; lfs_dir_t dir; int i; char *fn; // 文件名 //打开目录 res = lfs_dir_open(&lfs_flash, &dir, path); if (res == LFS_ERR_OK) { i = strlen(path); for (;;) { //读取目录下的内容,再读会自动读下一个文件 res = lfs_dir_read(&lfs_flash, &dir, &fno); //为空时表示所有项目读取完毕,跳出 if (res != true || fno.name[0] == 0) break; #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.name; #else fn = fno.name; #endif //点表示当前目录,跳过 if (*fn == '.') continue; //目录,递归读取 if (fno.type & LFS_TYPE_DIR) { //合成完整目录名 sprintf(&path[i], "/%s", fn); // //递归遍历 // res = func_record_lfs_scan_files(path); // path[i] = 0; // //打开失败,跳出循环 // if (res != LFS_ERR_OK) // break; } else { printf("%s/%s\n", path, fn); //输出文件名 /* 可以在这里提取特定格式的文件路径 */ }//else } //for } lfs_dir_close(&lfs_flash, &fs_record_obj.dir); return res; } /*------------------------------------------------------ 读取指定目录下所有的文件 说明: lfs_dir_read 按顺序读取目录内文件, 重复调用此函数可读取目录内所有文件; ---------------------------------------------------------*/ void func_record_lfs_files_update(char * path) { char file_name[32] = {0}; lfs_soff_t res; //部分在递归过程被修改的变量,不用全局变量 struct lfs_info fno = {0}; fs_record_obj.items_num = 0; fs_record_obj.file_num = 0; memset((void *)fs_record_obj.file_list, 0x00,sizeof(fs_record_obj.file_list)); memset((void *)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); //获取fatfs文件系统 fs_record_obj.free_size = mid_lfs_flash_get_free(); #if _USE_LFN//如果使能支持长文件名 先对下面两项初始化 fileinfo.lfsize=_MAX_LFN * 2 + 1;// fileinfo.lfname=(TCHAR*)FileName;// #endif res = lfs_dir_open(&lfs_flash, &fs_record_obj.dir,(const char*)path); if(res != LFS_ERR_OK)/* 打开文件夹目录成功,目录信息已经在dir结构体中保存 */ { res = lfs_mkdir(&lfs_flash, (const char*)path); if(res == LFS_ERR_OK) { fs_record_obj.fs_stat = true; return; } else { return; } } fs_record_obj.fs_stat = true; //打开日志路径正常,获取路文件夹内的文件列表 while(lfs_dir_read(&lfs_flash, &fs_record_obj.dir, &fno) == true) //读文件信息到文件状态结构体中 { fs_record_obj.items_num++; //判定的顺序不能变 if(!fno.name[0]) break; //如果文件名为‘\0',说明读取完成结束 if (fno.type & LFS_TYPE_DIR) continue; //表示目录,跳过 if (fno.name[0] == '.') continue; //点表示当前目录,跳过 if( (fs_record_obj.file_num < MAX_FILE_COUNT) &&(strstr(fno.name,FILE_START) == fno.name) &&((strstr(fno.name,FILE_END) != 0)) ) { sprintf((char *)fs_record_obj.file_list[fs_record_obj.file_num], "%s/%s", fs_record_obj.fold,fno.name);//将文件名存入列表中 fs_record_obj.file_num ++; } else { /* 如果目录已经存在,关闭它 */ res = lfs_dir_close(&lfs_flash, &fs_record_obj.dir); sprintf((char *)file_name,"%s/%s",fs_record_obj.fold, fno.name); //输出文件名 taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_remove(&lfs_flash, file_name); taskEXIT_CRITICAL(); /* 临界保护关闭 */ if(LFS_ERR_OK != res) { fs_record_obj.fs_stat = false; return; } } } /* 如果目录已经存在,关闭它 */ res = lfs_dir_close(&lfs_flash, &fs_record_obj.dir); if(fs_record_obj.file_num > 0) { } else { memset((void *)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send)); return; } //按文件名最小到大排序; if(fs_record_obj.file_num > 1) { func_record_lfs_dir_qsort(fs_record_obj.file_num); } //获取最新的文件; uint8_t max_idx = fs_record_obj.file_num - 1; sprintf((char *)fs_record_obj.name_send,"%s", fs_record_obj.file_list[max_idx]); //如果文件个数超限, if((fs_record_obj.file_num > NUM_FILE_SET) ||(fs_record_obj.free_size < 500)) { //删除日期最早的文件 sprintf((char *)file_name,"%s", fs_record_obj.file_list[0]); taskENTER_CRITICAL(); /* 临界保护开启 */ res = lfs_remove(&lfs_flash, file_name); taskEXIT_CRITICAL(); /* 临界保护关闭 */ if(LFS_ERR_OK != res) { fs_record_obj.fs_stat = false; return; } } UNUSED(res); return; } int qsort_cmp(const void *a,const void *b) { return strcmp(( char * ) a, (const char* )b); } //(void * /*base*/, size_t /*nmemb*/, size_t /*size*/, int (* /*compar*/)(const void *, const void *)) __attribute__((__nonnull__(1,4))); void func_record_lfs_dir_qsort(size_t fcount) { qsort((void *)fs_record_obj.file_list, fcount, sizeof(fs_record_obj.file_list[0]), qsort_cmp); } void func_record_lfs_init(void) { memset(fs_record_obj.file_list, 0x00,sizeof(fs_record_obj.file_list)); //清空文件列表 fs_record_obj.file_num = 0; fs_record_obj.fs_stat = true; func_record_lfs_files_update((char *)fs_record_obj.fold); } typedef struct record_lfs_object { uint32_t cnts; uint8_t test_flag; char buf[LFS_PAGE_SIZE]; }record_lfs_OBJ; record_lfs_OBJ record_lfs_obj; void func_record_lfs_fs_test(void) { record_lfs_obj.cnts++; sprintf(record_lfs_obj.buf,"XX%08xXX",record_lfs_obj.cnts); switch(record_lfs_obj.test_flag) { case 0: { func_record_lfs_write((uint8_t *)record_lfs_obj.buf ,strlen(record_lfs_obj.buf)); }break; case 1: { func_record_lfs_read((uint8_t *)record_lfs_obj.buf ,sizeof(record_lfs_obj.buf)); func_record_lfs_delete((uint8_t *)record_lfs_obj.buf ,sizeof(record_lfs_obj.buf)); func_record_lfs_read((uint8_t *)record_lfs_obj.buf ,sizeof(record_lfs_obj.buf)); }break; default: { func_record_lfs_files_update((char *)fs_record_obj.fold); func_record_lfs_read((uint8_t *)record_lfs_obj.buf ,sizeof(record_lfs_obj.buf)); }break; } } char path_buf[512] = {0}; void func_record_lfs_main(void const *argument) { #if USE_SPI_FLASH func_w25q_init(); func_w25q_test(); #endif #if USE_LFS_RECORD taskENTER_CRITICAL(); mid_lfs_flash_init(); mid_lfs_flash_bootcnt(); mid_lfs_flash_boot_step(); taskEXIT_CRITICAL(); func_record_queue_init(); func_record_queue_update(); #endif osDelay(1000);// func_record_lfs_init(); while(1) { strcpy(path_buf,fs_record_obj.fold); //func_record_lfs_scan_files(path_buf); func_record_lfs_fs_test(); osDelay(1000); } } #endif //---------------------------USE_LFS_RECORD---------------------------- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/