38 #define likely(x) __builtin_expect(!!(x), 1)
39 #define unlikely(x) __builtin_expect(!!(x), 0)
42 #define MIN(x , y) (((x) < (y)) ? (x) : (y))
45 #define MAX(x , y) (((x) > (y)) ? (x) : (y))
47 #define IS_POWER_OF_TWO(s) ((s) && !((s) & ((s) - 1)))
49 #ifndef SDLOG_NUM_FILES
50 #error SDLOG_NUM_FILES should be defined in mcuconf.h
55 #define FFCONF_DEF _FATFS
59 #if _FS_SHARE != 0 && _FS_SHARE < SDLOG_NUM_FILES
60 #error if _FS_SHARE is not zero, it should be equal of superior to SDLOG_NUM_FILES
64 #else // FFCONF_DEF > 8000
65 #if FF_FS_LOCK != 0 && FF_FS_LOCK < SDLOG_NUM_FILES
66 #error if FF_FS_LOCK is not zero, it should be equal of superior to SDLOG_NUM_FILES
70 #ifndef SDLOG_ALL_BUFFERS_SIZE
71 #error SDLOG_ALL_BUFFERS_SIZE should be defined in mcuconf.h
74 #if SDLOG_ALL_BUFFERS_SIZE > 65536
75 #error constraint 512 <= SDLOG_ALL_BUFFERS_SIZE <= 65536 not meet
78 #define SDLOG_WRITE_BUFFER_SIZE (SDLOG_ALL_BUFFERS_SIZE/SDLOG_NUM_FILES)
80 #ifndef SDLOG_MAX_MESSAGE_LEN
81 #error SDLOG_MAX_MESSAGE_LENshould be defined in mcuconf.h
84 #ifndef SDLOG_QUEUE_BUCKETS
85 #error SDLOG_QUEUE_BUCKETS should be defined in mcuconf.h
88 #if FF_FS_REENTRANT == 0
89 #warning "FF_FS_REENTRANT = 0 in ffconf.h DO NOT open close file during log"
92 #if SDLOG_WRITE_BUFFER_SIZE < 512
93 #error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES cannot be < 512
96 #if (!(IS_POWER_OF_TWO (SDLOG_WRITE_BUFFER_SIZE)))
97 #error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES should be a POWER OF 2
100 #ifdef SDLOG_NEED_QUEUE
125 #define WRITE_BYTE_CACHE_SIZE 15 // limit overhead :
137 struct FilePoolUnit {
140 systime_t lastFlushTs;
145 LogMessage *writeByteCache;
151 .fil = {{0}}, .inUse =
false, .tagAtClose =
false,
152 .writeByteCache = NULL, .writeByteSeek = 0
156 static volatile size_t nbBytesWritten = 0;
166 struct _SdLogBuffer {
173 #define LOG_MESSAGE_PREBUF_LEN (SDLOG_MAX_MESSAGE_LEN+sizeof(LogMessage))
174 #endif // SDLOG_NEED_QUEUE
179 #ifdef SDLOG_NEED_QUEUE
180 static size_t logMessageLen(
const LogMessage *lm);
181 static size_t logRawLen(
const size_t len);
182 static SdioError sdLoglaunchThread(
void);
184 static thread_t *sdLogThd = NULL;
186 static void removeFromQueue(
const size_t nbMsgToRFemov);
187 static void cleanQueue(
const bool allQueue);
188 static SdioError sdLogExpandLogFile(
const FileDes fileObject,
const size_t sizeInMo,
189 const bool preallocate);
191 #if (CH_KERNEL_MAJOR > 2)
192 static void thdSdLog(
void *arg) ;
194 static msg_t thdSdLog(
void *arg) ;
197 #endif // SDLOG_NEED_QUEUE
209 if (sdLogThd != NULL) {
214 #ifdef SDLOG_NEED_QUEUE
218 if (!sdc_lld_is_card_inserted(NULL)) {
224 chThdSleepMilliseconds(10);
231 #if FFCONF_DEF < 8000
232 FRESULT rc = f_mount(0, &fatfs);
234 FRESULT rc = f_mount(&fatfs,
"/", 1);
241 if (freeSpaceInKo != NULL) {
242 f_getfree(
"/", &clusters, &fsp);
243 *freeSpaceInKo = clusters * (
uint32_t)fatfs.csize / 2;
246 #ifdef SDLOG_NEED_QUEUE
248 fileDes[i].inUse = fileDes[i].tagAtClose =
false;
249 fileDes[i].writeByteCache = NULL;
250 fileDes[i].writeByteSeek = 0;
253 storageStatus = sdLoglaunchThread();
257 return storageStatus;
264 #if FFCONF_DEF < 8000
265 FRESULT rc = f_mount(0, NULL);
267 FRESULT rc = f_mount(NULL,
"", 0);
282 #ifdef SDLOG_NEED_QUEUE
284 const uint32_t autoFlushPeriod,
const bool appendTagAtClose,
285 const size_t sizeInMo,
const bool preallocate,
char *fileName,
const size_t nameLength)
299 sde = getNextFIL(&ldf);
301 return storageStatus = sde;
304 sde =
getFileName(prefix, directoryName, fileName, nameLength, +1);
311 rc = f_open(&fileDes[ldf].fil, fileName, FA_WRITE | FA_CREATE_ALWAYS);
313 fileDes[ldf].inUse =
false;
316 fileDes[ldf].tagAtClose = appendTagAtClose;
317 fileDes[ldf].autoFlushPeriod = autoFlushPeriod;
318 fileDes[ldf].lastFlushTs = 0;
319 sde = sdLogExpandLogFile(ldf, sizeInMo, preallocate);
323 return storageStatus = sde;
331 if (flush ==
false) {
338 if (fileDes[fd].inUse) {
339 FIL *
fo = &fileDes[
fd].fil;
340 if (fileDes[fd].tagAtClose) {
341 f_write(fo,
"\r\nEND_OF_LOG\r\n", 14, &bw);
342 nbBytesWritten += bw;
344 FRESULT trc = f_close(fo);
345 fileDes[
fd].inUse =
false;
358 if (sdLogThd == NULL) {
365 if (fileDes[fd].inUse) {
376 lm->op.fcntl = FCNTL_EXIT;
392 if (sdLogThd == NULL) {
399 if (fileDes[fd].inUse) {
400 status = sdLogFlushLog(fd);
407 return storageStatus =
status;
411 #define FD_CHECK(fd) if ((fd < 0) || (fd >= SDLOG_NUM_FILES) \
412 || (fileDes[fd].inUse == false)) \
413 return SDLOG_FATFS_ERROR
417 const bool preallocate)
422 const FRESULT rc = f_expand(&fileDes[fd].fil, sizeInMo * 1024 * 1024, preallocate);
445 lm->op.fcntl = FCNTL_WRITE;
446 lm->op.fd = fd & 0x1f;
452 const size_t msgLen = logMessageLen(lm);
483 lm->op.fcntl = FCNTL_FLUSH;
484 lm->op.fd = fd & 0x1f;
503 lm->op.fcntl = FCNTL_CLOSE;
504 lm->op.fd = fd & 0x1f;
521 if (
unlikely(fileDes[fd].writeByteCache != NULL)) {
522 if (
msgqueue_send(&messagesQueue, fileDes[fd].writeByteCache,
523 sizeof(LogMessage) + fileDes[fd].writeByteSeek,
527 fileDes[
fd].writeByteCache = NULL;
547 lm->op.fcntl = FCNTL_WRITE;
548 lm->op.fd = fd & 0x1f;
549 memcpy(lm->mess, buffer, len);
579 return sdb->lm->mess + sdb->offset;
584 if ((sdb->offset + offset) < sdb->len) {
594 return sdb->len - sdb->offset;
601 if ((fd < 0) || (fd >= SDLOG_NUM_FILES) || (fileDes[fd].inUse ==
false)) {
612 sdb->lm->op.fcntl = FCNTL_WRITE;
613 sdb->lm->op.fd = fd & 0x1f;
628 return storageStatus =
status;
639 if (fileDes[fd].writeByteCache == NULL) {
645 lm->op.fcntl = FCNTL_WRITE;
646 lm->op.fd = fd & 0x1f;
648 fileDes[
fd].writeByteCache = lm;
649 fileDes[
fd].writeByteSeek = 0;
651 lm = fileDes[
fd].writeByteCache;
654 lm->mess[fileDes[
fd].writeByteSeek++] = value;
656 if (fileDes[fd].writeByteSeek == WRITE_BYTE_CACHE_SIZE) {
661 fileDes[
fd].writeByteSeek = 0;
671 #define WA_LOG_BASE_SIZE 1024
674 static THD_WORKING_AREA(waThdSdLog, WA_LOG_BASE_SIZE+((_MAX_LFN+1)*2)+(19*32));
684 chThdSleepMilliseconds(100);
686 sdLogThd = chThdCreateStatic(waThdSdLog,
sizeof(waThdSdLog),
687 NORMALPRIO + 1, thdSdLog, NULL);
688 if (sdLogThd == NULL) {
699 storageStatus = retVal;
700 if (sdLogThd == NULL) {
718 lm.op.fcntl = FCNTL_EXIT;
725 return storageStatus = retVal;
731 char *nextFileName,
const size_t nameLength,
const int indexOffset)
740 const size_t directoryNameLen =
MIN(strlen(directoryName), 128);
741 const size_t slashDirNameLen = directoryNameLen + 2;
742 char slashDirName[slashDirNameLen];
743 strlcpy(slashDirName,
"/", slashDirNameLen);
744 strlcat(slashDirName, directoryName, slashDirNameLen);
746 rc = f_opendir(&dir, directoryName);
748 rc = f_mkdir(slashDirName);
752 rc = f_opendir(&dir, directoryName);
759 rc = f_readdir(&dir, &fno);
760 if (rc != FR_OK || fno.fname[0] == 0) {
break; }
763 if (fno.fname[0] ==
'.') {
continue; }
765 if (!(fno.fattrib & AM_DIR)) {
768 maxCurrentIndex =
MAX(maxCurrentIndex, fileIndex);
775 rc = f_closedir(&dir);
782 directoryName, prefix, maxCurrentIndex + indexOffset);
785 chsnprintf(nextFileName, nameLength,
"%s\\%s%.ERR",
786 directoryName, prefix);
798 rc = f_opendir(&dir, directoryName);
804 rc = f_readdir(&dir, &fno);
805 if (rc != FR_OK || fno.fname[0] == 0) {
break; }
807 if (fno.fname[0] ==
'.') {
continue; }
809 if (!(fno.fattrib & AM_DIR)) {
811 if ((strncmp(fno.fname, prefix, strlen(prefix)) == 0) && (fno.fsize <= sizeConsideredEmpty)) {
812 char absPathName[128];
813 strlcpy(absPathName, directoryName,
sizeof(absPathName));
814 strlcat(absPathName,
"/",
sizeof(absPathName));
815 strlcat(absPathName, fno.fname,
sizeof(absPathName));
816 rc = f_unlink(absPathName);
828 rc = f_closedir(&dir);
853 const size_t len = strlen(prefix);
856 if (strncmp(prefix, fileName, len) != 0) {
861 const char *suffix = &(fileName[len]);
864 if (!isdigit((
int) suffix[0])) {
873 #ifdef SDLOG_NEED_QUEUE
874 static void cleanQueue(
const bool allQueue)
876 if (allQueue ==
false) {
880 const size_t freeRam = stat.mfree;
882 const bool queue_full = (chMBGetFreeCountI(&messagesQueue.
mb) <= 0);
885 if ((freeRam < 200) || (queue_full ==
true)) {
896 static void removeFromQueue(
const size_t nbMsgToRFemove)
908 LogMessage *lm = NULL;
909 for (
size_t i = 0; i < nbMsgToRFemove; i++) {
927 #if (CH_KERNEL_MAJOR > 2)
928 static void thdSdLog(
void *arg)
930 static msg_t thdSdLog(
void *arg)
943 chRegSetThreadName("thdSdLog");
945 LogMessage *lm = NULL;
948 FIL *fo = &fileDes[lm->op.fd].fil;
949 uint8_t *
const perfBuffer = perfBuffers[lm->op.fd].buffer;
951 switch (lm->op.fcntl) {
955 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
956 if (fileDes[lm->op.fd].inUse) {
958 f_write(fo, perfBuffer, curBufFill, &bw);
959 nbBytesWritten += bw;
960 perfBuffers[lm->op.fd].size = 0;
962 if (lm->op.fcntl == FCNTL_FLUSH) {
965 if (fileDes[lm->op.fd].tagAtClose) {
966 f_write(fo,
"\r\nEND_OF_LOG\r\n", 14, &bw);
967 nbBytesWritten += bw;
970 fileDes[lm->op.fd].inUse =
false;
984 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
985 if (fileDes[lm->op.fd].inUse) {
987 if (messLen < (SDLOG_WRITE_BUFFER_SIZE - curBufFill)) {
989 memcpy(&(perfBuffer[curBufFill]), lm->mess, (
size_t)(messLen));
990 perfBuffers[lm->op.fd].size = (
uint16_t)((perfBuffers[lm->op.fd].size) + messLen);
993 const int32_t stayLen = SDLOG_WRITE_BUFFER_SIZE - curBufFill;
994 memcpy(&(perfBuffer[curBufFill]), lm->mess, (
size_t)(stayLen));
995 FRESULT rc = f_write(fo, perfBuffer, SDLOG_WRITE_BUFFER_SIZE, &bw);
996 nbBytesWritten += bw;
999 if (fileDes[lm->op.fd].autoFlushPeriod) {
1000 const systime_t now = chVTGetSystemTimeX();
1001 if ((now - fileDes[lm->op.fd].lastFlushTs) >
1004 fileDes[lm->op.fd].lastFlushTs = now;
1010 }
else if (bw != SDLOG_WRITE_BUFFER_SIZE) {
1014 memcpy(perfBuffer, &(lm->mess[stayLen]), (
uint32_t)(messLen - stayLen));
1015 perfBuffers[lm->op.fd].size = (
uint16_t)(messLen - stayLen);
1025 #if (CH_KERNEL_MAJOR == 2)
1030 static size_t logMessageLen(
const LogMessage *lm)
1035 static size_t logRawLen(
const size_t len)
1037 return sizeof(LogMessage) + len;
1046 if (fileDes[i].inUse ==
false) {
1048 fileDes[i].inUse =
true;
1055 size_t sdLogGetNbBytesWrittenToStorage(
void)
1057 return nbBytesWritten;
1062 return storageStatus;
SdioError sdLogFinish(void)
unmount filesystem
Specific RAM section for DMA usage on F7.
int32_t msgqueue_pop_timeout(MsgQueue *que, void **msgPtr, const systime_t timout)
receive message specifying timeout
static IN_DMA_SECTION(FATFS fatfs)
Mini printf-like functionality.
arch independent SDIO API
#define IN_STD_SECTION_CLEAR(var)
static SdioError flushWriteByteBuffer(const FileDes fd)
#define SDLOG_WRITE_BUFFER_SIZE
void msgqueue_init(MsgQueue *que, tlsf_memory_heap_t *heap, msg_t *mb_buf, const cnt_t mb_size)
initialise MsgQueue
#define SDLOG_MAX_MESSAGE_LEN
void chsnprintf(char *buffer, size_t size, const char *fmt,...)
static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
int32_t msgqueue_copy_send(MsgQueue *que, const void *msg, const uint16_t msgLen, const MsgQueueUrgency urgency)
send a buffer NOT previously allocated
bool sdio_disconnect(void)
Disconnect a SD card on SDIO peripheral.
void tlsf_free_r(tlsf_memory_heap_t *heap, void *ptr)
void tlsf_stat_r(tlsf_memory_heap_t *heap, struct tlsf_stat_t *stat)
SdioError sdLogInit(uint32_t *freeSpaceInKo)
initialise sdLog
SdioError getFileName(const char *prefix, const char *directoryName, char *nextFileName, const size_t nameLength, const int indexOffset)
get last used name for a pattern, then add offset and return valid filename
#define SDLOG_QUEUE_BUCKETS
bool sdio_connect(void)
Connect a SD card on SDIO peripheral.
static const float offset[]
void * tlsf_realloc_r(tlsf_memory_heap_t *heap, void *ptr, size_t bytes)
SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
remove spurious log file left on sd
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
void chvsnprintf(char *buffer, size_t size, const char *fmt, va_list ap)
int32_t msgqueue_pop(MsgQueue *que, void **msgPtr)
wait then receive message
int32_t msgqueue_send(MsgQueue *que, void *msg, const uint16_t msgLen, const MsgQueueUrgency urgency)
send a buffer previously allocated by msgqueue_malloc_before_send
#define IN_DMA_SECTION_CLEAR(var)
#define CH_CFG_ST_FREQUENCY
System tick frequency.
struct _SdLogBuffer SdLogBuffer
void * tlsf_malloc_r(tlsf_memory_heap_t *heap, size_t bytes)