diff --git a/Libraries/riff_file/src/riff_file_fatfs.c b/Libraries/riff_file/src/riff_file_fatfs.c index 6037b44a..0abf11da 100644 --- a/Libraries/riff_file/src/riff_file_fatfs.c +++ b/Libraries/riff_file/src/riff_file_fatfs.c @@ -3,8 +3,15 @@ #include "ql_riff.h" #include "riff_internal.h" #include +#include +#include +#include #include "dbg_uart.h" +#if (RIFF_AUTO_SEQUENCE_FILENAMES == 1) +void riff_delete_oldest_qlsm(void); +#endif + /* list of all known RIFF files */ static struct riff_file all_riff_files[ RIFF_MAX_FILES ]; @@ -132,7 +139,7 @@ int RIFF_file_write_object( struct riff_object *pObject ) size_t fileSize = f_size(pObject->pFile->pFile); if (fileSize > RIFF_FILE_SIZE_MAX) { - dbg_str_int("riff file size limit reached", fileSize); + //dbg_str_int("riff file size limit reached", fileSize); uint32_t sticks, eticks; sticks = xTaskGetTickCount(); f_close(pObject->pFile->pFile); @@ -143,8 +150,10 @@ int RIFF_file_write_object( struct riff_object *pObject ) { dbg_str_str("datafile", nextfilename); } + // Now delete the oldest file + riff_delete_oldest_qlsm(); eticks = xTaskGetTickCount(); - dbg_str_int("f_close + f_open took", eticks-sticks); + //dbg_str_int("f_close + f_open took", eticks-sticks); } #endif /* update the actual bytes in the riff header */ @@ -175,11 +184,164 @@ int RIFF_file_write_object( struct riff_object *pObject ) } #if (RIFF_AUTO_SEQUENCE_FILENAMES == 1) +#include +#define RIFF_FILE_COUNT_MAX (10) +#define RIFF_FILE_BASENAME ("data_") +/* Hold the file numbers (in sorted order) that are present on the card + * (data_.qlsm). A 0 indicates there is no file with that number + */ +static int riff_file_num_buff[RIFF_FILE_COUNT_MAX] = {0}; +static int sfilenumHead = -1; // new/next file number to be created +static int sfilenumTail = -1; // oldest file number to be deleted + +static bool riff_file_num_buff_init_done = false; static int riff_file_count = 0; -static char riff_file_basename[64]= "data_"; +static char riff_file_basename[64]= RIFF_FILE_BASENAME; static char riff_file_nextname[64]; +static char riff_file_oldname[64]; +/* File number management */ +void riff_filenum_print_buf(void) +{ + char tmpb[16]; + dbg_str("File numbers: "); + for (int k = 0; k < RIFF_FILE_COUNT_MAX; k++) + { + dbg_str(itoa(riff_file_num_buff[k], tmpb, 10)); + dbg_str(", "); + } + dbg_str_int_noln("Head", sfilenumHead); + dbg_str_int_noln(", Tail", sfilenumTail); + dbg_str("\n"); +} + +/** @brief Get head and tail of file numbers + * + * riff_file_num_buff[] contains the file numbers currently on the + * SD card. Scan for a gap to identify the new filename to be created + * and the oldest file that needs to be deleted. + * + * If scan identifies following file numbers + * 001, 002, 003, 004, 005, 008, 009, 010 + * then delete 008 and create 006 as in the below + * 001, 002, 003, 004, 005, 006, 009, 010 + * + */ +int riff_filenum_get_head_tail(int *pfilenumTail) +{ + int filenumHead, filenumTail; + filenumHead = -1; + filenumTail = -1; + + for (int k = 1; k <= RIFF_FILE_COUNT_MAX; k++) + { + if (riff_file_num_buff[k-1] == 0) + { // first break + if (riff_file_num_buff[(k%RIFF_FILE_COUNT_MAX)] == 0) + { + // we have a break + filenumHead = k; // new file name will be k + filenumTail = (k+1)%(RIFF_FILE_COUNT_MAX) + 1; // old filename to delete + } + else if (k==1) + { + filenumHead = RIFF_FILE_COUNT_MAX; + filenumTail = 2; + } + else + { // there is an error, force a break + filenumHead = k; // new file name will be k + // delete the file (k+1) + sfilenumTail = k%(RIFF_FILE_COUNT_MAX) + 1; // delete the extra file + riff_delete_oldest_qlsm(); + filenumTail = (k+1)%(RIFF_FILE_COUNT_MAX) + 1; // old filename to delete + } + break; + } + } + + *pfilenumTail = filenumTail; + return filenumHead; +} + +/** @brief Search a directory for to identify new file number to be created and + * oldest *.qlsm file to be deleted. The new file number is returned + * and the oldest file number is stored at the address `pfilenumTail` + * + * @param pdir directory to be searched + * @param pfilenumTail address to store the oldest file number to be deleted + * + * @return new file number to be created + */ +int riff_file_scan_qlsm_files (TCHAR *pdir, int *pfilenumTail) +{ + FRESULT fr; /* Return value */ + DIR dj; /* Directory object */ + FILINFO fno; /* File information */ + FILINFO oldest_fno; + int ifilenum, tot_count, nitems; + int filenumHead, filenumTail, filenumOffset; + + if (riff_file_num_buff_init_done == false) + { + for (int k = 0; k < RIFF_FILE_COUNT_MAX; k++) + riff_file_num_buff[k] = 0; + tot_count = 0; + fr = f_findfirst(&dj, &fno, pdir, "?*.qlsm"); /* Start to search for QLSM files */ + + while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */ + ifilenum = 0; + nitems = 0; + filenumOffset = strlen(riff_file_basename); + if (strncmp (fno.fname, riff_file_basename, filenumOffset) == 0) + { + nitems = sscanf(fno.fname+filenumOffset, "%d.qlsm", &ifilenum); /* scan for the file number */ + } + if (nitems <= 0) + continue; + if ((ifilenum > 0) && (ifilenum <= RIFF_FILE_COUNT_MAX)) { + tot_count++; + riff_file_num_buff[ifilenum-1] = ifilenum; + } + fr = f_findnext(&dj, &fno); /* Search for next item */ + } + + f_closedir(&dj); + } + + filenumHead = riff_filenum_get_head_tail(&filenumTail); + *pfilenumTail = filenumTail; + return filenumHead; +} + +void riff_filenum_init(void) +{ + sfilenumHead = riff_file_scan_qlsm_files("", &sfilenumTail); + return; +} + +/** @brief Delete oldest file identified by the file number in sfilenumTail + * static variable + */ +void riff_delete_oldest_qlsm(void) +{ + int filenum; + + filenum = sfilenumTail; + snprintf(riff_file_oldname, sizeof(riff_file_oldname), "%s%08d.qlsm", riff_file_basename, filenum); + dbg_str_str_nonl("Deleting", riff_file_oldname); + if (f_unlink(riff_file_oldname) == FR_OK) + { + dbg_str(" Successful\n"); + } + else + { + dbg_str(" Failed\n"); + } + riff_file_num_buff[filenum-1] = 0; -/** @brief RIFF fileformat initialization function using the +} + +/** @brief RIFF file format initialization function using the * user provided basename and the initial file number integer * New riff filenames will be constructed in the format * basenameIIIIIIII.qlsm where IIIIIIII is an integer @@ -189,24 +351,47 @@ static char riff_file_nextname[64]; */ void riff_filename_format_init(char *basename, int ifilenum) { - strncpy(riff_file_basename, basename, sizeof(riff_file_basename)); - riff_file_count = ifilenum; + extern int riff_file_scan_qlsm_files (TCHAR *pdir, int *pfilenumTail); + if (riff_file_num_buff_init_done == true) + return; + + strncpy(riff_file_basename, basename, sizeof(riff_file_basename)); + riff_filenum_init(); + riff_file_num_buff_init_done = true; } /** @brief Get a new RIFF filename for storing the sensor data - * A new filename of the format - * @param[out] newfilename pointer a char array of atleast 64 bytes + * A new filename of the format: .qlsm where + * is the file basename specified in riff_file_basename + * and is the new file number + * + * @return newfilename pointer to a char array of atleast 64 bytes + * */ char *riff_get_newfilename(void) { - riff_file_count++; - snprintf(riff_file_nextname, sizeof(riff_file_nextname), "%s%08d.qlsm", riff_file_basename, riff_file_count); - return riff_file_nextname; + extern int riff_file_scan_qlsm_files (TCHAR *pdir, int *pfilenumTail); + + int k, filenumHead, filenumTail; + if (riff_file_num_buff_init_done == false) + riff_filename_format_init(riff_file_basename, 0); + + sfilenumHead = riff_file_scan_qlsm_files("", &sfilenumTail); + riff_filenum_print_buf(); + riff_file_count = sfilenumHead; + snprintf(riff_file_nextname, sizeof(riff_file_nextname), "%s%08d.qlsm", riff_file_basename, riff_file_count); + dbg_str_str_nonl("Next filename", riff_file_nextname); + riff_file_num_buff[riff_file_count-1] = riff_file_count; + dbg_str("\n"); + + return riff_file_nextname; } size_t RIFF_get_filesize(void) { } + + #endif /* RIFF_AUTO_SEQUENCE_FILENAMES */ #endif /* USE_FATFS_APIS */ diff --git a/Tasks/fs_monitor/inc/fs_monitor.h b/Tasks/fs_monitor/inc/fs_monitor.h index 8380b9a8..0ef5ca68 100644 --- a/Tasks/fs_monitor/inc/fs_monitor.h +++ b/Tasks/fs_monitor/inc/fs_monitor.h @@ -21,6 +21,9 @@ #include "Fw_global_config.h" +// Set this to 1 to print disk usage at monitor intervals +#define FS_MONITOR_ENABLE_PRINTS (1) + // Default low threshold value of available free space as a percentage of total available space // Override in Fw_global_config.h to set a different value #ifndef FS_MONITOR_LOW_DISK_SPACE_THRESHOLD diff --git a/Tasks/fs_monitor/src/fs_monitor.c b/Tasks/fs_monitor/src/fs_monitor.c index bf5a7e19..9629addd 100644 --- a/Tasks/fs_monitor/src/fs_monitor.c +++ b/Tasks/fs_monitor/src/fs_monitor.c @@ -23,6 +23,8 @@ #include "dbg_uart.h" #include "fs_monitor.h" +#include + #if (USE_FATFS_APIS == 1) #include "ff.h" #else @@ -48,6 +50,9 @@ __attribute__ ((weak)) void riff_low_disk_space(void) */ void fs_monitor_task(void *pParameter) { +#if FS_MONITOR_ENABLE_PRINTS == 1 + char buff[256]; +#endif /* FS_MONITOR_ENABLE_PRINTS */ while (1) { vTaskDelay(1000 * pdMS_TO_TICKS(FS_MONITOR_INTERVAL)); @@ -58,10 +63,10 @@ void fs_monitor_task(void *pParameter) totsect = (pfs->n_fatent - 2) * pfs->csize; nsect = nclust * pfs->csize; iperc = (nsect * 100L) / totsect ; - //dbg_str_int_noln("Free space: ", nsect/2); - //dbg_str_int_noln(" Total space: ", totsect/2); - //dbg_str_int_noln(" ", iperc); - //dbg_str("% disk space available\n"); +#if FS_MONITOR_ENABLE_PRINTS == 1 + snprintf(buff, 256, "%10d kB [%3d%%] free of %10d kB total\n", nsect, iperc, totsect); + dbg_str(buff); +#endif if ( iperc <= FS_MONITOR_LOW_DISK_SPACE_THRESHOLD) { riff_low_disk_space(); diff --git a/qf_apps/qf_ssi_ai_app/GCC_Project/makefiles/Makefile_fs_monitor b/qf_apps/qf_ssi_ai_app/GCC_Project/makefiles/Makefile_fs_monitor index 44e0744f..68380c6d 100644 --- a/qf_apps/qf_ssi_ai_app/GCC_Project/makefiles/Makefile_fs_monitor +++ b/qf_apps/qf_ssi_ai_app/GCC_Project/makefiles/Makefile_fs_monitor @@ -4,6 +4,6 @@ FS_MONITOR_SRCS:=$(wildcard $(FS_MONITOR_DIR)/*.c) SRCS:=$(notdir $(FS_MONITOR_SRCS)) OBJS:=$(addprefix $(OUTPUT_PATH)/,$(SRCS:.c=.o)) SRC_PATH:= $(FS_MONITOR_DIR) -$(info FS_MONITOR_SRCS = ${FS_MONITOR_SRCS}, SRCS=${SRCS}) + include $(COMMON_STUB) diff --git a/qf_apps/qf_ssi_ai_app/README.rst b/qf_apps/qf_ssi_ai_app/README.rst index 1c33fd4d..e99e8860 100644 --- a/qf_apps/qf_ssi_ai_app/README.rst +++ b/qf_apps/qf_ssi_ai_app/README.rst @@ -102,7 +102,7 @@ to use a new file each time the size reaches the limit specified in this macro. :: /* Select the maximum file size for storing the sensor data */ - #define RIFF_FILE_SIZE_MAX (1024*4*25) // 100KB + #define RIFF_FILE_SIZE_MAX (1024*4*256*1024) // 1GB Filename conventions ~~~~~~~~~~~ @@ -119,6 +119,29 @@ source file `Fw_global_config.h `__. #define USE_DCL_FILENAME_ONLY (0) +When RIFF_AUTO_SEQUENCE_FILENAMES is selected, filenames are auto sequenced +from the set of { data_00000001, data_00000002, ..., data_}, where +the macro RIFF_FILE_MAX_COUNT defined `riff_file_fatfs.c `__ +is the number of files that would be managed by this application. When the +count approaches this maximum value, old files are removed a new file is +created. As an example, for RIFF_FILE_MAX_COUNT=10, if the current set of +files on the SD card are as below: + +:: + + { data_00000001.qlsm, data_00000002.qlsm, data_00000003.qlsm, data_00000004.qlsm, data_00000005.qlsm, + data_00000008.qlsm, data_00000009.qlsm, data_00000010.qlsm } + +the applicaion would remove the file data_00000008.qlsm and create data_00000006.qlsm, +resulting in the following list of files: + +:: + + { data_00000001.qlsm, data_00000002.qlsm, data_00000003.qlsm, data_00000004.qlsm, data_00000005.qlsm, + data_00000006.qlsm, data_00000009.qlsm, data_00000010.qlsm } + + + 1. Verify that the following macros is set for saving data to SD card To save recognition results to the SD card, enable the macro S3AI_FIRMWARE_DATASAVE in diff --git a/qf_apps/qf_ssi_ai_app/inc/app_config.h b/qf_apps/qf_ssi_ai_app/inc/app_config.h index 341663b5..14bc994c 100644 --- a/qf_apps/qf_ssi_ai_app/inc/app_config.h +++ b/qf_apps/qf_ssi_ai_app/inc/app_config.h @@ -36,8 +36,8 @@ /*######################## DATA CAPTURE METHOD ################################*/ -#define S3AI_FIRMWARE_LIVESTREAM 0 /* Enable livestream via SSI Interface (supports sensor or recognition) */ -#define S3AI_FIRMWARE_DATASAVE 1 /* Enable SD card for collection (supports sensor and recognition) */ +#define S3AI_FIRMWARE_LIVESTREAM 1 /* Enable livestream via SSI Interface (supports sensor or recognition) */ +#define S3AI_FIRMWARE_DATASAVE 0 /* Enable SD card for collection (supports sensor and recognition) */ @@ -103,4 +103,4 @@ typedef struct st_fw_global_config #error "Enable only one of S3AI_FIRMWARE_IS_COLLECTION and S3AI_FIRMWARE_IS_RECOGNITION for S3AI_FIRMWARE_LIVESTREAM" #endif -#endif \ No newline at end of file +#endif diff --git a/qf_apps/qf_ssi_ai_app/src/main.c b/qf_apps/qf_ssi_ai_app/src/main.c index 0bb59712..06094be5 100644 --- a/qf_apps/qf_ssi_ai_app/src/main.c +++ b/qf_apps/qf_ssi_ai_app/src/main.c @@ -155,7 +155,23 @@ int main(void) ((SSI_SENSOR_SELECT_AUDIO == 1) && (SENSOR_AUDIO_LIVESTREAM_ENABLED == 1)) ) StartSimpleStreamingInterfaceTask(); #endif - xTaskSet_uSecCount(1546300800ULL * 1000ULL * 1000ULL); // start at 2019-01-01 00:00:00 UTC time + // set current date and time + struct tm curtim; + char currtimeStr[32] = "2021-07-15 00:00:00"; + sscanf(currtimeStr, "%d-%d-%d %d:%d:%d", + &curtim.tm_year, &curtim.tm_mon, &curtim.tm_mday, + &curtim.tm_hour, &curtim.tm_min, &curtim.tm_sec); + curtim.tm_year -= 1900; + curtim.tm_mon--; + snprintf(currtimeStr, 32, "%04d-%02d-%02d %02d:%02d:%02d ", + curtim.tm_year+1900, curtim.tm_mon+1, curtim.tm_mday, + curtim.tm_hour, curtim.tm_min, curtim.tm_sec); + dbg_str(currtimeStr); + + uint32_t unixTime = 1546300800UL; + unixTime = mktime(&curtim); + ql_sys_settime(unixTime); + xTaskSet_uSecCount((uint64_t)unixTime * 1000ULL * 1000ULL); // start at 2019-01-01 00:00:00 UTC time #if (S3AI_FIRMWARE_DATASAVE == 1) start_fs_monitor_task();