/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * 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_FATFS_RECORD==1
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "func_fatfs.h"
#include "dev_spi_sdcard.h"
#include "func_spi_w25qxx.h"
#include "func_fatfs_record.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 -----------------------------------------------*/



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];			//最老的文件名
	
	FIL 			opt_file;					//当前操作的文件
	FATFS 		fs;	
	DIR 			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,
};

//add boly 20221020
//uint8_t  data_buf[16*1024] = {0};
//end boly
void 	func_record_Get_Capacity(void);
void func_record_files_update(char * path);
void func_record_dir_qsort(size_t fcount);

extern SDateTime m_datetime;
/* Private user code ---------------------------------------------------------*/

uint8_t func_record_fatfs_isOK(void)
{
		
		return fs_record_obj.fs_stat;
}

uint8_t func_record_fatfs_set_OK(uint8_t stat)
{
		fs_record_obj.fs_stat = stat;
		return fs_record_obj.fs_stat;
}

void func_record_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_write(uint8_t *buf ,uint32_t len)
{
		
	FRESULT res;
	UINT 		write_len = 0;

	//根据日期生成文件名，用于文件写入
	func_record_mk_fileName((char *)fs_record_obj.name_new);
	
	//打开当前存在的文件；
	res = f_open(&fs_record_obj.opt_file,(char *)fs_record_obj.name_new , FA_WRITE| FA_OPEN_EXISTING);
	if(FR_OK != res)
	{
		//检查文件个数是否超限
		func_record_files_update((char *)fs_record_obj.fold);
		
		if(FR_NO_FILE == res)
		{			
			//创建文件并写入
			res = f_open(&fs_record_obj.opt_file, (char*)fs_record_obj.name_new, FA_WRITE| FA_CREATE_NEW);
			if(FR_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 = f_size(&fs_record_obj.opt_file);
	
	//操作指针移动到文件末尾
	res = f_lseek(&fs_record_obj.opt_file, fs_record_obj.opt_len);
	
	taskENTER_CRITICAL();    /* 临界保护开启 */
	res = f_write(&fs_record_obj.opt_file, buf, len, &write_len);	
	res = f_close(&fs_record_obj.opt_file);		//关闭文件	
	taskEXIT_CRITICAL();    /* 临界保护关闭 */
	
 	return write_len;
}

void func_record_get_NameSend(void)
{
	//发送文件是否存在
	if(strlen((char*)fs_record_obj.name_send) > 0)
	{
		return;
	}

	
	//检查文件个数是否超限
	func_record_files_update((char *)fs_record_obj.fold);
}

/**
  * @brief  The application entry point.
  * @retval int
  */
uint32_t func_record_read(uint8_t *buf, uint32_t len)
{
	FRESULT res;
	
	//uint32_t 		file_len = 0;
	uint32_t 		read_len = 0;
	
	func_record_get_NameSend();
	
	if(strlen((char *)fs_record_obj.name_send) <= 0)
	{
		return 0;
	}
	
	res = f_open(&fs_record_obj.opt_file, (char*)fs_record_obj.name_send, FA_READ | FA_OPEN_EXISTING);
	if(FR_OK != res)
	{	
		return 0;
	}		
	
	fs_record_obj.opt_len = f_size(&fs_record_obj.opt_file);
	
	//如果文件小于数据长度，则删除文件
	if(fs_record_obj.opt_len < len)
	{
			res = f_close(&fs_record_obj.opt_file);
		
			taskENTER_CRITICAL();    /* 临界保护开启 */
			res = f_unlink((char*)fs_record_obj.name_send);
			taskEXIT_CRITICAL();    /* 临界保护关闭 */
		
			if(res == FR_OK)
			{
				memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send));
			}
			return 0;
	};
	res = f_lseek(&fs_record_obj.opt_file, fs_record_obj.opt_len - len);
	
	res = f_read(&fs_record_obj.opt_file, buf, len, &read_len);
	
	res = f_close(&fs_record_obj.opt_file);
	
		
	return read_len;
}

uint32_t func_record_remove(uint8_t *buf, uint32_t len)
{
	FRESULT res;

	uint32_t 		read_len = 0;
	
	func_record_get_NameSend();
	
	if(strlen((char *)fs_record_obj.name_send) <= 0)
	{
		return 0;
	}
	
	res = f_open(&fs_record_obj.opt_file, (char*)fs_record_obj.name_send, FA_WRITE| FA_READ| FA_OPEN_EXISTING);
	if(FR_OK != res)
	{	
		memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send));
		return 0;
	}		
	
	fs_record_obj.opt_len = f_size(&fs_record_obj.opt_file);
	
	//如果文件小于数据长度，则删除文件
	if(fs_record_obj.opt_len < len)
	{
			res = f_close(&fs_record_obj.opt_file);
			taskENTER_CRITICAL();    /* 临界保护开启 */
			res = f_unlink((char*)fs_record_obj.name_send);
			taskEXIT_CRITICAL();    /* 临界保护关闭 */
			if(res == FR_OK)
			{
				memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send));
			}
			return 0;
	};
	res = f_lseek(&fs_record_obj.opt_file, fs_record_obj.opt_len - len);	
	res = f_read(&fs_record_obj.opt_file, buf, len, &read_len);
	
	res = f_lseek(&fs_record_obj.opt_file, fs_record_obj.opt_len - len);	
	
	taskENTER_CRITICAL();    /* 临界保护开启 */
	res = f_truncate(&fs_record_obj.opt_file ); 		//截断后面的文件
	res = f_close(&fs_record_obj.opt_file);	
	taskEXIT_CRITICAL();    /* 临界保护关闭 */	
		
	return read_len;
}

uint32_t func_record_delete(uint8_t *buf,uint32_t len)
{
	FRESULT res;
	//uint32_t file_len = 0;
	
	if(strlen((char *)fs_record_obj.name_send) <= 0)
	{
		return 0;
	}
	//打开文件
	res = f_open(&fs_record_obj.opt_file, (char*)fs_record_obj.name_send, FA_WRITE | FA_OPEN_EXISTING );
	
	if ( res != FR_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 = f_size(&fs_record_obj.opt_file);
	//如果文件小于数据长度，则删除文件
	if(fs_record_obj.opt_len <= len)
	{
		res = f_close(&fs_record_obj.opt_file);
		taskENTER_CRITICAL();    /* 临界保护开启 */
		res = f_unlink((char*)fs_record_obj.name_send);
		taskEXIT_CRITICAL();    /* 临界保护关闭 */
		if(res == FR_OK)
		{
			memset((char*)fs_record_obj.name_send, 0x00,sizeof(fs_record_obj.name_send));
		}
		return 0;			
	};
	
	res = f_lseek(&fs_record_obj.opt_file, fs_record_obj.opt_len - len);
	taskENTER_CRITICAL();    /* 临界保护开启 */
	res = f_truncate(&fs_record_obj.opt_file ); 		//截断后面的文件
	taskEXIT_CRITICAL();    /* 临界保护关闭 */	
	res = f_close(&fs_record_obj.opt_file);	
	
	return res;
}



/**
  * 文件信息获取
  */
FRESULT func_record_file_check(void)
{ 
	FRESULT f_res;                    /* 文件操作结果 */	
  static FILINFO finfo;
  /* 获取文件信息 */
  f_res=f_stat("TestDir/testdir.txt",&finfo);
  if(f_res==FR_OK)
  {
    printf("“testdir.txt”文件信息：\n");
    printf("》文件大小: %ld(字节)\n", finfo.fsize);
    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%c%c%c\n\n",
           (finfo.fattrib & AM_DIR) ? 'D' : '-',      // 是一个目录
           (finfo.fattrib & AM_RDO) ? 'R' : '-',      // 只读文件
           (finfo.fattrib & AM_HID) ? 'H' : '-',      // 隐藏文件
           (finfo.fattrib & AM_SYS) ? 'S' : '-',      // 系统文件
           (finfo.fattrib & AM_ARC) ? 'A' : '-');     // 档案文件
  }
  return f_res;
}

/**
  * @brief  scan_files 递归扫描FatFs内的文件
  * @param  path:初始扫描路径
  * @retval result:文件系统的返回值
  */
FRESULT func_record_scan_files (char* path) 
{ 
  FRESULT res; 		//部分在递归过程被修改的变量，不用全局变量	
  FILINFO fno; 
	DIR 		dir;	
  int i;            
  char *fn;        // 文件名	
	
#if _USE_LFN 
  /* 长文件名支持 */
  /* 简体中文需要2个字节保存一个“字”*/
  static char lfn[_MAX_LFN*2 + 1]; 	
  fno.fname = lfn; 
  fno.fsize = sizeof(lfn); 
#endif 
  //打开目录
  res = f_opendir(&dir, path); 
  if (res == FR_OK) 
	{ 
    i = strlen(path); 
    for (;;) 
		{ 
      //读取目录下的内容，再读会自动读下一个文件
      res = f_readdir(&dir, &fno); 								
      //为空时表示所有项目读取完毕，跳出
      if (res != FR_OK || fno.fname[0] == 0) break; 	
#if _USE_LFN 
      fn = *fno.lfname ? fno.lfname : fno.fname; 
#else 
      fn = fno.fname; 
#endif 
      //点表示当前目录，跳过			
      if (*fn == '.') continue; 	
      //目录，递归读取      
      if (fno.fattrib & AM_DIR)         
			{ 			
        //合成完整目录名        
        sprintf(&path[i], "/%s", fn); 		
        //递归遍历         
        res = func_record_scan_files(path);	
        path[i] = 0;         
        //打开失败，跳出循环        
        if (res != FR_OK) 
					break; 
      } 
			else 
			{ 
				printf("%s/%s\n", path, fn);								//输出文件名	
        /* 可以在这里提取特定格式的文件路径 */        
      }//else
    } //for
  } 
	
	
  return res; 
}


/*------------------------------------------------------
 读取指定目录下所有的文件
 说明:
  f_readdir    按顺序读取目录内文件，
 重复调用此函数可读取目录内所有文件；
---------------------------------------------------------*/
void func_record_files_update(char * path)
{		
		char file_name[32] = {0};
	  FRESULT res; 		//部分在递归过程被修改的变量，不用全局变量		
	  FILINFO 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 = func_fatfs_get_free();
		
#if _USE_LFN//如果使能支持长文件名 先对下面两项初始化
    fileinfo.lfsize=_MAX_LFN * 2 + 1;//
    fileinfo.lfname=(TCHAR*)FileName;//
#endif
    if(f_opendir(&fs_record_obj.dir,(const char*)path) != FR_OK)/* 打开文件夹目录成功，目录信息已经在dir结构体中保存 */
    {
			res = f_mkdir((const char*)path);
			if(res == FR_OK)
			{
				fs_record_obj.fs_stat = true;
				return;
			}
			else
			{				
				return;
			}
		}		
		
		fs_record_obj.fs_stat = true;
		
		//打开日志路径正常,获取路文件夹内的文件列表
		while(f_readdir(&fs_record_obj.dir, &fno) == FR_OK)  	//读文件信息到文件状态结构体中
		{		
				fs_record_obj.items_num++;
				//判定的顺序不能变			
				if(!fno.fname[0]) break; 													//如果文件名为‘\0'，说明读取完成结束

				if (fno.fattrib & AM_DIR)	continue; 						  //表示目录，跳过	
			
				if (fno.fname[0] == '.') continue; 								//点表示当前目录，跳过				

						
				if( (fs_record_obj.file_num < MAX_FILE_COUNT)
					&&(strstr(fno.fname,FILE_START) == fno.fname)
				  &&((strstr(fno.fname,FILE_END) != 0))
				)
				{
						sprintf((char *)fs_record_obj.file_list[fs_record_obj.file_num], "%s/%s", fs_record_obj.fold,fno.fname);//将文件名存入列表中
						fs_record_obj.file_num ++;	
				}
				else
				{	
					/* 如果目录已经存在，关闭它 */
					res = f_closedir(&fs_record_obj.dir);	
					
					sprintf((char *)file_name,"%s/%s",fs_record_obj.fold, fno.fname);								//输出文件名	
					taskENTER_CRITICAL();    /* 临界保护开启 */
					res = f_unlink(file_name);
					taskEXIT_CRITICAL();    /* 临界保护关闭 */
					if(FR_OK != res)
					{
											
						fs_record_obj.fs_stat = false;
						return;
					}
				}
    }
		
		/* 如果目录已经存在，关闭它 */
		res = f_closedir(&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_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 = f_unlink(file_name);
			taskEXIT_CRITICAL();    /* 临界保护关闭 */
			
			if(FR_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_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_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_files_update((char *)fs_record_obj.fold);
}


void func_record_fs_test(void)
{	
	
	record_test_obj.cnts++;
	sprintf(record_test_obj.buf,"XX%08xXX",record_test_obj.cnts);
	switch(record_test_obj.test_flag)
	{
		case 0:
		{
			func_record_write((uint8_t *)record_test_obj.buf ,strlen(record_test_obj.buf));
		}break;
		case 1:
		{
			func_record_read((uint8_t *)record_test_obj.buf ,sizeof(record_test_obj.buf));
			func_record_delete((uint8_t *)record_test_obj.buf ,sizeof(record_test_obj.buf));
			func_record_read((uint8_t *)record_test_obj.buf ,sizeof(record_test_obj.buf));
		}break;
		default:
		{
			func_record_read((uint8_t *)record_test_obj.buf ,sizeof(record_test_obj.buf));
		}break;
		
	}
	
}


char*  pstr = 0;
char*  pidx = 0;
void func_record_str(void)
{
	char  str_name[] ="20221112.TXT" ;

	while(1)
	{
		pstr =  strstr(str_name,FILE_START);
		
		pidx =  strstr(str_name,FILE_END);
		UNUSED(pstr);
		UNUSED(pidx);
	}
}
char path_buf[512] = {0};
void func_record_fatfs_main(void const *argument)
{
	//func_record_str();

	
	//add boly 20221014  SD卡 FATFS组件初始化	
#if USE_SPI_SD	
  SDCARD_GPIO_Init();
  SDCARD_SPI_Init();
#endif
	
#if USE_SPI_FLASH	
  func_w25q_init();
	func_w25q_test();
#endif
		
	
	
#if USE_FATFS_RECORD	
	taskENTER_CRITICAL();	
	func_fatfs_init();
	func_fatfs_main();
	taskEXIT_CRITICAL();
	
	func_record_queue_init();
	func_record_queue_update();
	
	//while(1)
	{
		osDelay(1000);
	};	
	//end boly
#endif

	osDelay(1000);//
	func_record_init();
	while(1)
	{
		strcpy(path_buf,fs_record_obj.fold);
		//func_fatfs_scan_files(path_buf);
		//func_record_fs_test();
		func_record_queue_test();
		func_record_work();
		osDelay(1000);
	}
}
#endif //---------------------------USE_FATFS_RECORD----------------------------

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
