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 #error upgrade FATFS to 0.14 at least
60 #else // FFCONF_DEF > 8000
61 #if FF_FS_LOCK != 0 && FF_FS_LOCK < SDLOG_NUM_FILES
62 #error if FF_FS_LOCK is not zero, it should be equal of superior to SDLOG_NUM_FILES
66 #ifndef SDLOG_ALL_BUFFERS_SIZE
67 #error SDLOG_ALL_BUFFERS_SIZE should be defined in mcuconf.h
70 #if SDLOG_ALL_BUFFERS_SIZE > 65536
71 #error constraint 512 <= SDLOG_ALL_BUFFERS_SIZE <= 65536 not meet
74 #define SDLOG_WRITE_BUFFER_SIZE (SDLOG_ALL_BUFFERS_SIZE/SDLOG_NUM_FILES)
76 #ifndef SDLOG_MAX_MESSAGE_LEN
77 #error SDLOG_MAX_MESSAGE_LENshould be defined in mcuconf.h
80 #ifndef SDLOG_QUEUE_BUCKETS
81 #error SDLOG_QUEUE_BUCKETS should be defined in mcuconf.h
84 #if FF_FS_REENTRANT == 0
85 #warning "FF_FS_REENTRANT = 0 in ffconf.h DO NOT open close file during log"
88 #if SDLOG_WRITE_BUFFER_SIZE < 512
89 #error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES cannot be < 512
92 #if (!(IS_POWER_OF_TWO (SDLOG_WRITE_BUFFER_SIZE)))
93 #error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES should be a POWER OF 2
96 #ifdef SDLOG_NEED_QUEUE
121 #define WRITE_BYTE_CACHE_SIZE 15 // limit overhead :
133 struct FilePoolUnit {
136 systime_t lastFlushTs;
141 LogMessage *writeByteCache;
147 .fil = {{0}}, .inUse =
false, .tagAtClose =
false,
148 .writeByteCache = NULL, .writeByteSeek = 0
152 static volatile size_t nbBytesWritten = 0;
162 struct _SdLogBuffer {
169 #define LOG_MESSAGE_PREBUF_LEN (SDLOG_MAX_MESSAGE_LEN+sizeof(LogMessage))
170 #endif // SDLOG_NEED_QUEUE
175 #ifdef SDLOG_NEED_QUEUE
176 static size_t logMessageLen(
const LogMessage *lm);
177 static size_t logRawLen(
const size_t len);
178 static SdioError sdLoglaunchThread(
void);
180 static thread_t *sdLogThd = NULL;
182 static void removeFromQueue(
const size_t nbMsgToRFemov);
183 static void cleanQueue(
const bool allQueue);
184 static SdioError sdLogExpandLogFile(
const FileDes fileObject,
const size_t sizeInMo,
185 const bool preallocate);
187 static void thdSdLog(
void *arg) ;
189 #endif // SDLOG_NEED_QUEUE
201 if (sdLogThd != NULL) {
206 #ifdef SDLOG_NEED_QUEUE
210 if (!sdc_lld_is_card_inserted(NULL)) {
216 chThdSleepMilliseconds(10);
223 #if FFCONF_DEF < 8000
224 FRESULT rc = f_mount(0, &fatfs);
226 FRESULT rc = f_mount(&fatfs,
"/", 1);
233 if (freeSpaceInKo != NULL) {
234 f_getfree(
"/", &clusters, &fsp);
235 *freeSpaceInKo = clusters * (
uint32_t)fatfs.csize / 2;
238 #ifdef SDLOG_NEED_QUEUE
240 fileDes[i].inUse = fileDes[i].tagAtClose =
false;
241 fileDes[i].writeByteCache = NULL;
242 fileDes[i].writeByteSeek = 0;
245 storageStatus = sdLoglaunchThread();
249 return storageStatus;
256 #if FFCONF_DEF < 8000
257 FRESULT rc = f_mount(0, NULL);
259 FRESULT rc = f_mount(NULL,
"", 0);
274 #ifdef SDLOG_NEED_QUEUE
276 const uint32_t autoFlushPeriod,
const bool appendTagAtClose,
277 const size_t sizeInMo,
const bool preallocate,
char *fileName,
const size_t nameLength)
291 sde = getNextFIL(&ldf);
293 return storageStatus = sde;
296 sde =
getFileName(prefix, directoryName, fileName, nameLength, +1);
303 rc = f_open(&fileDes[ldf].fil, fileName, FA_WRITE | FA_CREATE_ALWAYS);
305 fileDes[ldf].inUse =
false;
308 fileDes[ldf].tagAtClose = appendTagAtClose;
309 fileDes[ldf].autoFlushPeriod = autoFlushPeriod;
310 fileDes[ldf].lastFlushTs = 0;
311 sde = sdLogExpandLogFile(ldf, sizeInMo, preallocate);
315 return storageStatus = sde;
323 if (flush ==
false) {
330 if (fileDes[
fd].inUse) {
331 FIL *
fo = &fileDes[
fd].fil;
332 if (fileDes[
fd].tagAtClose) {
333 f_write(
fo,
"\r\nEND_OF_LOG\r\n", 14, &bw);
334 nbBytesWritten += bw;
336 FRESULT trc = f_close(
fo);
337 fileDes[
fd].inUse =
false;
350 if (sdLogThd == NULL) {
357 if (fileDes[
fd].inUse) {
368 lm->op.fcntl = FCNTL_EXIT;
384 if (sdLogThd == NULL) {
391 if (fileDes[
fd].inUse) {
399 return storageStatus =
status;
403 #define FD_CHECK(fd) if ((fd < 0) || (fd >= SDLOG_NUM_FILES) \
404 || (fileDes[fd].inUse == false)) \
405 return SDLOG_FATFS_ERROR
409 const bool preallocate)
414 const FRESULT rc = f_expand(&fileDes[
fd].fil, sizeInMo * 1024 * 1024, preallocate);
437 lm->op.fcntl = FCNTL_WRITE;
438 lm->op.fd =
fd & 0x1f;
444 const size_t msgLen = logMessageLen(lm);
475 lm->op.fcntl = FCNTL_FLUSH;
476 lm->op.fd =
fd & 0x1f;
495 lm->op.fcntl = FCNTL_CLOSE;
496 lm->op.fd =
fd & 0x1f;
513 if (
unlikely(fileDes[
fd].writeByteCache != NULL)) {
515 sizeof(LogMessage) + fileDes[
fd].writeByteSeek,
519 fileDes[
fd].writeByteCache = NULL;
539 lm->op.fcntl = FCNTL_WRITE;
540 lm->op.fd =
fd & 0x1f;
541 memcpy(lm->mess, buffer, len);
571 return sdb->lm->mess + sdb->offset;
576 if ((sdb->offset +
offset) < sdb->len) {
586 return sdb->len - sdb->offset;
604 sdb->lm->op.fcntl = FCNTL_WRITE;
605 sdb->lm->op.fd =
fd & 0x1f;
620 return storageStatus =
status;
631 if (fileDes[
fd].writeByteCache == NULL) {
637 lm->op.fcntl = FCNTL_WRITE;
638 lm->op.fd =
fd & 0x1f;
640 fileDes[
fd].writeByteCache = lm;
641 fileDes[
fd].writeByteSeek = 0;
643 lm = fileDes[
fd].writeByteCache;
646 lm->mess[fileDes[
fd].writeByteSeek++] = value;
648 if (fileDes[
fd].writeByteSeek == WRITE_BYTE_CACHE_SIZE) {
653 fileDes[
fd].writeByteSeek = 0;
663 #define WA_LOG_BASE_SIZE 1024
676 chThdSleepMilliseconds(100);
678 sdLogThd = chThdCreateStatic(waThdSdLog,
sizeof(waThdSdLog),
679 NORMALPRIO + 1, thdSdLog, NULL);
680 if (sdLogThd == NULL) {
691 storageStatus = retVal;
692 if (sdLogThd == NULL) {
710 lm.op.fcntl = FCNTL_EXIT;
717 return storageStatus = retVal;
723 char *nextFileName,
const size_t nameLength,
const int indexOffset)
732 const size_t directoryNameLen =
MIN(strlen(directoryName), 128);
733 const size_t slashDirNameLen = directoryNameLen + 2;
734 char slashDirName[slashDirNameLen];
735 strlcpy(slashDirName,
"/", slashDirNameLen);
736 strlcat(slashDirName, directoryName, slashDirNameLen);
738 rc = f_opendir(&
dir, directoryName);
740 rc = f_mkdir(slashDirName);
744 rc = f_opendir(&
dir, directoryName);
751 rc = f_readdir(&
dir, &fno);
752 if (rc != FR_OK || fno.fname[0] == 0) {
break; }
755 if (fno.fname[0] ==
'.') {
continue; }
757 if (!(fno.fattrib & AM_DIR)) {
760 maxCurrentIndex =
MAX(maxCurrentIndex, fileIndex);
767 rc = f_closedir(&
dir);
774 directoryName, prefix, maxCurrentIndex + indexOffset);
777 chsnprintf(nextFileName, nameLength,
"%s\\%s%.ERR",
778 directoryName, prefix);
790 rc = f_opendir(&
dir, directoryName);
796 rc = f_readdir(&
dir, &fno);
797 if (rc != FR_OK || fno.fname[0] == 0) {
break; }
799 if (fno.fname[0] ==
'.') {
continue; }
801 if (!(fno.fattrib & AM_DIR)) {
803 if ((strncmp(fno.fname, prefix, strlen(prefix)) == 0) && (fno.fsize <= sizeConsideredEmpty)) {
804 char absPathName[128];
805 strlcpy(absPathName, directoryName,
sizeof(absPathName));
806 strlcat(absPathName,
"/",
sizeof(absPathName));
807 strlcat(absPathName, fno.fname,
sizeof(absPathName));
808 rc = f_unlink(absPathName);
820 rc = f_closedir(&
dir);
845 const size_t len = strlen(prefix);
848 if (strncmp(prefix, fileName, len) != 0) {
853 const char *suffix = &(fileName[len]);
856 if (!isdigit((
int) suffix[0])) {
865 #ifdef SDLOG_NEED_QUEUE
866 static void cleanQueue(
const bool allQueue)
868 if (allQueue ==
false) {
872 const size_t freeRam = stat.mfree;
874 const bool queue_full = (chMBGetFreeCountI(&messagesQueue.
mb) <= 0);
877 if ((freeRam < 200) || (queue_full ==
true)) {
888 static void removeFromQueue(
const size_t nbMsgToRFemove)
900 LogMessage *lm = NULL;
901 for (
size_t i = 0; i < nbMsgToRFemove; i++) {
919 static void thdSdLog(
void *arg)
931 chRegSetThreadName("thdSdLog");
933 LogMessage *lm = NULL;
936 FIL *
fo = &fileDes[lm->op.fd].fil;
937 uint8_t *
const perfBuffer = perfBuffers[lm->op.fd].buffer;
939 switch (lm->op.fcntl) {
943 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
944 if (fileDes[lm->op.fd].inUse) {
946 f_write(
fo, perfBuffer, curBufFill, &bw);
947 nbBytesWritten += bw;
948 perfBuffers[lm->op.fd].size = 0;
950 if (lm->op.fcntl == FCNTL_FLUSH) {
953 if (fileDes[lm->op.fd].tagAtClose) {
954 f_write(
fo,
"\r\nEND_OF_LOG\r\n", 14, &bw);
955 nbBytesWritten += bw;
958 fileDes[lm->op.fd].inUse =
false;
972 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
973 if (fileDes[lm->op.fd].inUse) {
977 memcpy(&(perfBuffer[curBufFill]), lm->mess, (
size_t)(messLen));
978 perfBuffers[lm->op.fd].size = (
uint16_t)((perfBuffers[lm->op.fd].size) + messLen);
982 memcpy(&(perfBuffer[curBufFill]), lm->mess, (
size_t)(stayLen));
984 nbBytesWritten += bw;
987 if (fileDes[lm->op.fd].autoFlushPeriod) {
988 const systime_t now = chVTGetSystemTimeX();
989 if ((now - fileDes[lm->op.fd].lastFlushTs) >
992 fileDes[lm->op.fd].lastFlushTs = now;
1002 memcpy(perfBuffer, &(lm->mess[stayLen]), (
uint32_t)(messLen - stayLen));
1003 perfBuffers[lm->op.fd].size = (
uint16_t)(messLen - stayLen);
1015 static size_t logMessageLen(
const LogMessage *lm)
1020 static size_t logRawLen(
const size_t len)
1022 return sizeof(LogMessage) + len;
1031 if (fileDes[i].inUse ==
false) {
1033 fileDes[i].inUse =
true;
1040 size_t sdLogGetNbBytesWrittenToStorage(
void)
1042 return nbBytesWritten;
1047 return storageStatus;