/* 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****/