Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
sdLog.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013-2016 Gautier Hattenberger, Alexandre Bustico
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22/*
23 * @file modules/loggers/sdlog_chibios/sdLog.c
24 * @brief sdlog API using ChibiOS and Fatfs
25 *
26 */
27
28#include <string.h>
29#include <stdlib.h>
30#include <ch.h>
31#include <hal.h>
32#include <ff.h>
34#include "printf.h"
35#include "mcu_periph/sdio.h"
36#include <ctype.h>
37
38#ifndef MIN
39#define MIN(x , y) (((x) < (y)) ? (x) : (y))
40#endif
41#ifndef MAX
42#define MAX(x , y) (((x) > (y)) ? (x) : (y))
43#endif
44#define IS_POWER_OF_TWO(s) ((s) && !((s) & ((s) - 1)))
45
46#ifndef SDLOG_NUM_FILES
47#error SDLOG_NUM_FILES should be defined in mcuconf.h
48#endif
49
50
51#ifndef FFCONF_DEF
52#define FFCONF_DEF _FATFS
53#endif
54
55#if FFCONF_DEF < 8000
56#error upgrade FATFS to 0.14 at least
57#else // FFCONF_DEF > 8000
58#if FF_FS_LOCK != 0 && FF_FS_LOCK < SDLOG_NUM_FILES
59#error if FF_FS_LOCK is not zero, it should be equal of superior to SDLOG_NUM_FILES
60#endif
61#endif
62
63#ifndef SDLOG_ALL_BUFFERS_SIZE
64#error SDLOG_ALL_BUFFERS_SIZE should be defined in mcuconf.h
65#endif
66
67#if SDLOG_ALL_BUFFERS_SIZE > 65536
68#error constraint 512 <= SDLOG_ALL_BUFFERS_SIZE <= 65536 not meet
69#endif
70
71#define SDLOG_WRITE_BUFFER_SIZE (SDLOG_ALL_BUFFERS_SIZE/SDLOG_NUM_FILES)
72
73#ifndef SDLOG_MAX_MESSAGE_LEN
74#error SDLOG_MAX_MESSAGE_LENshould be defined in mcuconf.h
75#endif
76
77#ifndef SDLOG_QUEUE_BUCKETS
78#error SDLOG_QUEUE_BUCKETS should be defined in mcuconf.h
79#endif
80
81#if FF_FS_REENTRANT == 0
82#warning "FF_FS_REENTRANT = 0 in ffconf.h DO NOT open close file during log"
83#endif
84
85#if SDLOG_WRITE_BUFFER_SIZE < 512
86#error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES cannot be < 512
87#endif
88
89#if (!(IS_POWER_OF_TWO (SDLOG_WRITE_BUFFER_SIZE)))
90#error SDLOG_ALL_BUFFERS_SIZE / SDLOG_NUM_FILES should be a POWER OF 2
91#endif
92
93#ifdef SDLOG_NEED_QUEUE
95
96#include "mcu_periph/ram_arch.h"
97
98
99/*
100 The buffers that do DMA are the caches (named buf) in the FIL and FATFS struct of fatfs library
101 It's the only buffers that have to reside in DMA capable memory.
102
103 The buffer associated with message queue, and the cache buffer for caching file write
104 could reside in non DMA capable memory.
105
106 stm32f4 : regular sram : 128ko, dma, slow
107 ccm sram : 64ko, no_dma, fast
108
109 stm32f7 : regular sram : 256ko, dma only possible if data cache are explicitely flushed, fast
110 dtcm sram : 64ko, dma, slow (no cache)
111
112 stm32h7 :
113 ram0nc (wx) : org = 0x24000000, len = 128k : non cached for DMA stuff
114 ram0 (wx) : org = 0x24000000, len = 384k : standard
115 ram1 (wx) : org = 0x30000000, len = 256k
116 ram2 (wx) : org = 0x30000000, len = 288k : ram1+ram3
117 ram3 (wx) : org = 0x30040000, len = 32k
118 ram4 (wx) : org = 0x38000000, len = 64k
119 ram5 (wx) : org = 0x20000000, len = 128k : DTCM : fast ram
120 ram6 (wx) : org = 0x00000000, len = 64k
121 ram7 (wx) : org = 0x38800000, len = 4k
122 */
123
124
125
126#ifdef STM32H7XX
127#define IN_SDMMC_DMA_SECTION(x) IN_SDMMC_SECTION(x)
128#define IN_SDMMC_DMA_SECTION_CLEAR(x) IN_SDMMC_SECTION_CLEAR(x)
129#define IN_SDMMC_DMA_SECTION_NOINIT(x) IN_SDMMC_SECTION_NOINIT(x)
130#else
131#define IN_SDMMC_DMA_SECTION(x) IN_DMA_SECTION(x)
132#define IN_SDMMC_DMA_SECTION_CLEAR(x) IN_DMA_SECTION_CLEAR(x)
133#define IN_SDMMC_DMA_SECTION_NOINIT(x) IN_DMA_SECTION_NOINIT(x)
134#endif
135/*
136 s*printf functions are supposed to be thread safe, but the ones provided by
137 newlib function are not. One has to use _s*printf_r family that take a
138 struct _reent as first parameter.
139 */
140
141// #pragma GCC diagnostic push
142// #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
143// static struct _reent reent = _REENT_INIT(reent);
144// #pragma GCC diagnostic pop
145
146
147
148
151
152#define WRITE_BYTE_CACHE_SIZE 15 // limit overhead :
153// malloc (15+1) occupies 20bytes
154typedef struct {
155 uint8_t fcntl: 2;
156 uint8_t fd: 6;
157} FileOp;
158
159struct LogMessage {
160 FileOp op;
161 char mess[0];
162};
163
164struct FilePoolUnit {
165 FIL fil;
168 bool inUse;
169 bool tagAtClose;
170 // optimise write byte by caching at send level now that we are based upon tlsf where
171 // allocation granularity is 16 bytes
174};
175
177 [0 ... SDLOG_NUM_FILES - 1] = {
178 .fil = {{0}}, .inUse = false, .tagAtClose = false,
179 .writeByteCache = NULL, .writeByteSeek = 0
180 }
181};
182
183static volatile size_t nbBytesWritten = 0;
185
186typedef enum {
187 FCNTL_WRITE = 0b00,
188 FCNTL_FLUSH = 0b01,
189 FCNTL_CLOSE = 0b10,
190 FCNTL_EXIT = 0b11
191} FileFcntl;
192
193struct _SdLogBuffer {
194 LogMessage *lm;
195 size_t len;
197} ;
198
199
200#define LOG_MESSAGE_PREBUF_LEN (SDLOG_MAX_MESSAGE_LEN+sizeof(LogMessage))
201#endif // SDLOG_NEED_QUEUE
202
203/* File system object */
205
206#ifdef SDLOG_NEED_QUEUE
207static size_t logMessageLen(const LogMessage *lm);
208static size_t logRawLen(const size_t len);
209static SdioError sdLoglaunchThread(void);
210static SdioError sdLogStopThread(void);
211static thread_t *sdLogThd = NULL;
213static void removeFromQueue(const size_t nbMsgToRFemov);
214static void cleanQueue(const bool allQueue);
215static SdioError sdLogExpandLogFile(const FileDes fileObject, const size_t sizeInMo,
216 const bool preallocate);
217
218static void thdSdLog(void *arg) ;
219
220#endif // SDLOG_NEED_QUEUE
221
222static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName) ;
224
226{
227 DWORD clusters = 0;
228 FATFS *fsp = NULL;
229 nbBytesWritten = 0;
230
231 // if init is already done, return ERROR
232 if (sdLogThd != NULL) {
233 *freeSpaceInKo = 0;
235 }
236
237#ifdef SDLOG_NEED_QUEUE
239#endif
240
243 }
244
245
249
250 if (sdio_connect(&SDLOG_SDIO) == FALSE) {
252 }
253
254#if FFCONF_DEF < 8000
255 FRESULT rc = f_mount(0, &fatfs);
256#else
257 FRESULT rc = f_mount(&fatfs, "/", 1);
258#endif
259
260 if (rc != FR_OK) {
262 }
263
264 if (freeSpaceInKo != NULL) {
265 f_getfree("/", &clusters, &fsp);
266 *freeSpaceInKo = clusters * (uint32_t)fatfs.csize / 2;
267 }
268
269#ifdef SDLOG_NEED_QUEUE
270 for (uint8_t i = 0; i < SDLOG_NUM_FILES; i++) {
271 fileDes[i].inUse = fileDes[i].tagAtClose = false;
272 fileDes[i].writeByteCache = NULL;
273 fileDes[i].writeByteSeek = 0;
274 }
275
277#else
279#endif
280 return storageStatus;
281
282}
283
284
286{
287#if FFCONF_DEF < 8000
288 FRESULT rc = f_mount(0, NULL);
289#else
290 FRESULT rc = f_mount(NULL, "", 0);
291#endif
292 if (rc != FR_OK) {
294 }
295
296 // if we mount, unmount, don't disconnect sdio
297 /* if (sdio_disconnect (&SDLOG_SDIO) == FALSE) */
298 /* return SDLOG_NOCARD; */
299
300 return storageStatus = SDLOG_OK;
301}
302
303
304
305#ifdef SDLOG_NEED_QUEUE
306SdioError sdLogOpenLog(FileDes *fd, const char *directoryName, const char *prefix,
307 const uint32_t autoFlushPeriod, const bool appendTagAtClose,
308 const size_t sizeInMo, const bool preallocate, char *fileName, const size_t nameLength)
309{
310 FRESULT rc; /* fatfs result code */
311 SdioError sde = SDLOG_OK; /* sdio result code */
312 //DIR dir; /* Directory object */
313 //FILINFO fno; /* File information object */
314
315 /* local file descriptor
316 using fd is a bad idea since fd is set before fatfs objets are coherents
317 in a multithreaded application where sdLogXXX are done before sdLogWriteLog is done
318 we can have a race condition. setting fd only when fatfs files are opened resolve the problem
319 */
320 FileDes ldf;
321
322 sde = getNextFIL(&ldf);
323 if (sde != SDLOG_OK) {
324 return storageStatus = sde;
325 }
326
328 if (sde != SDLOG_OK) {
329 // sd card is not inserted, so logging task can be deleted
330 fileDes[ldf].inUse = false;
332 }
333
334
336 if (rc) {
337 fileDes[ldf].inUse = false;
339 } else {
340 fileDes[ldf].tagAtClose = appendTagAtClose;
341 fileDes[ldf].autoFlushPeriod = autoFlushPeriod;
342 fileDes[ldf].lastFlushTs = 0;
344 }
345
346 *fd = ldf;
347 return storageStatus = sde;
348}
349
351{
352 FRESULT rc = 0; /* Result code */
353
354 // do not flush what is in ram, close as soon as possible
355 if (flush == false) {
356 UINT bw;
357 // stop worker thread then close file
358 cleanQueue(true);
360
361 for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
362 if (fileDes[fd].inUse) {
363 FIL *fo = &fileDes[fd].fil;
364 if (fileDes[fd].tagAtClose) {
365 f_write(fo, "\r\nEND_OF_LOG\r\n", 14, &bw);
367 }
369 fileDes[fd].inUse = false;
370 if (!rc) {
371 rc = trc;
372 }
373 }
374 }
375
376 if (rc) {
378 }
379
380 // flush ram buffer then close
381 } else { // flush == true
382 if (sdLogThd == NULL) {
383 // something goes wrong, log thread is no more working
385 }
386
387 // queue flush + close order, then stop worker thread
388 for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
389 if (fileDes[fd].inUse) {
392 }
393 }
394
396 if (lm == NULL) {
398 }
399
400 lm->op.fcntl = FCNTL_EXIT;
401
404 } else {
406 sdLogThd = NULL;
407 }
408
409 }
410 return storageStatus = SDLOG_OK;
411}
412
414{
416 if (sdLogThd == NULL) {
417 // something goes wrong, log thread is no more working
419 }
420
421 // queue flush + close order, then stop worker thread
422 for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
423 if (fileDes[fd].inUse) {
425 if (status != SDLOG_OK) {
426 break;
427 }
428 }
429 }
430
431 return storageStatus = status;
432}
433
434
435#define FD_CHECK(fd) if ((fd < 0) || (fd >= SDLOG_NUM_FILES) \
436 || (fileDes[fd].inUse == false)) \
437 return SDLOG_FATFS_ERROR
438
439
441 const bool preallocate)
442{
443 FD_CHECK(fd);
444
445 // expand with opt=1 : pre allocate file now
446 const FRESULT rc = f_expand(&fileDes[fd].fil, sizeInMo * 1024 * 1024, preallocate);
447 return (rc == FR_OK) ? SDLOG_OK : SDLOG_CANNOT_EXPAND;
448}
449
450SdioError sdLogWriteLog(const FileDes fd, const char *fmt, ...)
451{
452 FD_CHECK(fd);
453
456 if (status != SDLOG_OK) {
457 return status;
458 }
459
460 va_list ap;
461 va_start(ap, fmt);
462
464 if (lm == NULL) {
465 va_end(ap);
467 }
468
469 lm->op.fcntl = FCNTL_WRITE;
470 lm->op.fd = fd & 0x1f;
471
472 chvsnprintf(lm->mess, SDLOG_MAX_MESSAGE_LEN - 1, fmt, ap);
473 lm->mess[SDLOG_MAX_MESSAGE_LEN - 1] = 0;
474 va_end(ap);
475
476 const size_t msgLen = logMessageLen(lm);
478 if (lm == NULL) {
480 }
481
484 }
485
486 return SDLOG_OK;
487}
488
490{
491 FD_CHECK(fd);
492
495 if (status != SDLOG_OK) {
496 return status;
497 }
498
499 // give room to send a flush order if the queue is full
500 cleanQueue(false);
501
503 if (lm == NULL) {
505 }
506
507 lm->op.fcntl = FCNTL_FLUSH;
508 lm->op.fd = fd & 0x1f;
509
512 }
513
514 return SDLOG_OK;
515}
516
518{
519 FD_CHECK(fd);
520
521 cleanQueue(false);
523 if (lm == NULL) {
525 }
526
527 lm->op.fcntl = FCNTL_CLOSE;
528 lm->op.fd = fd & 0x1f;
529
532 }
533
534 return storageStatus = SDLOG_OK;
535}
536
537
538
539
540
541static inline SdioError flushWriteByteBuffer(const FileDes fd)
542{
543 FD_CHECK(fd);
544
548 MsgQueue_REGULAR) < 0) {
550 }
551 fileDes[fd].writeByteCache = NULL;
552 }
553 return storageStatus = SDLOG_OK;
554}
555
556SdioError sdLogWriteRaw(const FileDes fd, const uint8_t *buffer, const size_t len)
557{
558 FD_CHECK(fd);
559
562 if (status != SDLOG_OK) {
563 return status;
564 }
565
567 if (lm == NULL) {
569 }
570
571 lm->op.fcntl = FCNTL_WRITE;
572 lm->op.fd = fd & 0x1f;
573 memcpy(lm->mess, buffer, len);
574
577 }
578
579 return SDLOG_OK;
580}
581
582SdioError sdLogAllocSDB(SdLogBuffer **sdb, const size_t len)
583{
585 if (*sdb == NULL) {
587 }
588
590 if (lm == NULL) {
593 }
594
595 (*sdb)->lm = lm;
596 (*sdb)->len = len;
597 (*sdb)->offset = 0;
598 return storageStatus = SDLOG_OK;
599}
600
602{
603 return sdb->lm->mess + sdb->offset;
604}
605
607{
608 if ((sdb->offset + offset) < sdb->len) {
609 sdb->offset += offset;
610 return true;
611 } else {
612 return false;
613 }
614}
615
617{
618 return sdb->len - sdb->offset;
619}
620
622{
624
625 if ((fd < 0) || (fd >= SDLOG_NUM_FILES) || (fileDes[fd].inUse == false)) {
627 goto fail;
628 }
629
631 if (status != SDLOG_OK) {
632 goto fail;
633 }
634
635
636 sdb->lm->op.fcntl = FCNTL_WRITE;
637 sdb->lm->op.fd = fd & 0x1f;
638
640 // msgqueue_send take care of freeing lm memory even in case of failure
641 // just need to free sdb memory
643 }
644
645 goto exit;
646
647fail:
649
650exit:
652 return storageStatus = status;
653}
654
655
656
657
658SdioError sdLogWriteByte(const FileDes fd, const uint8_t value)
659{
660 FD_CHECK(fd);
661 LogMessage *lm;
662
663 if (fileDes[fd].writeByteCache == NULL) {
665 if (lm == NULL) {
667 }
668
669 lm->op.fcntl = FCNTL_WRITE;
670 lm->op.fd = fd & 0x1f;
671
672 fileDes[fd].writeByteCache = lm;
673 fileDes[fd].writeByteSeek = 0;
674 } else {
675 lm = fileDes[fd].writeByteCache;
676 }
677
678 lm->mess[fileDes[fd].writeByteSeek++] = value;
679
682 // message is not sent so allocated buffer will not be released by receiver side
683 // instead of freeing buffer, we just reset cache seek.
684 if (status == SDLOG_QUEUEFULL) {
685 fileDes[fd].writeByteSeek = 0;
687 }
688 }
689 return storageStatus = SDLOG_OK;
690}
691
692/*
693 if fatfs use stack for working buffers, stack size should be reserved accordingly
694 */
695#define WA_LOG_BASE_SIZE 1024
696#if FF_USE_LFN == 2
697#if FF_FS_EXFAT
699#else
701#endif
702#else
704#endif
705
707{
709
711 NORMALPRIO + 1, thdSdLog, NULL);
712 if (sdLogThd == NULL) {
714 } else {
715 return storageStatus = SDLOG_OK;
716 }
717}
718
720{
722
724 if (sdLogThd == NULL) {
726 }
727
729
730 /* // ask for closing (after flushing) all opened files */
731 /* for (uint8_t i=0; i<SDLOG_NUM_FILES; i++) { */
732 /* if (fileDes[i].inUse) { */
733 /* flushWriteByteBuffer (i); */
734 /* lm.op.fcntl = FCNTL_CLOSE; */
735 /* lm.op.fd = i & 0x1f; */
736 /* if (msgqueue_copy_send (&messagesQueue, &lm, sizeof(LogMessage), MsgQueue_OUT_OF_BAND) < 0) { */
737 /* retVal= SDLOG_QUEUEFULL; */
738 /* } */
739 /* } */
740 /* } */
741
742 lm.op.fcntl = FCNTL_EXIT;
745 }
746
748 sdLogThd = NULL;
749 return storageStatus = retVal;
750}
751#endif
752
753
754SdioError getFileName(const char *prefix, const char *directoryName,
755 char *nextFileName, const size_t nameLength, const int indexOffset)
756{
757 DIR dir; /* Directory object */
758 FRESULT rc; /* Result code */
759 FILINFO fno; /* File information object */
762
763
764 const size_t directoryNameLen = MIN(strlen(directoryName), 128);
765 const size_t slashDirNameLen = directoryNameLen + 2;
769
771 if (rc != FR_OK) {
773 if (rc != FR_OK) {
775 }
777 if (rc != FR_OK) {
779 }
780 }
781
782 for (;;) {
783 rc = f_readdir(&dir, &fno); /* Read a directory item */
784 if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
785
786
787 if (fno.fname[0] == '.') { continue; }
788
789 if (!(fno.fattrib & AM_DIR)) {
790 // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
793 }
794 }
795 if (rc) {
797 }
798
799 rc = f_closedir(&dir);
800 if (rc) {
802 }
803
807 return storageStatus = SDLOG_OK;
808 } else {
809 chsnprintf(nextFileName, nameLength, "%s\\%s%.ERR",
812 }
813}
814
815SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
816{
817 DIR dir; /* Directory object */
818 FRESULT rc; /* Result code */
819 FILINFO fno; /* File information object */
820
821
823 if (rc != FR_OK) {
825 }
826
827 for (;;) {
828 rc = f_readdir(&dir, &fno); /* Read a directory item */
829 if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
830
831 if (fno.fname[0] == '.') { continue; }
832
833 if (!(fno.fattrib & AM_DIR)) {
834 // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
835 if ((strncmp(fno.fname, prefix, strlen(prefix)) == 0) && (fno.fsize <= sizeConsideredEmpty)) {
836 char absPathName[128];
838 strlcat(absPathName, "/", sizeof(absPathName));
839 strlcat(absPathName, fno.fname, sizeof(absPathName));
841 if (rc) {
842 break;
843 }
844 }
845 }
846 }
847
848 if (rc) {
850 }
851
852 rc = f_closedir(&dir);
853 if (rc) {
855 }
856
857 return storageStatus = SDLOG_OK;
858}
859
860/*
861# _____ _ _
862# | __ \ (_) | |
863# | |__) | _ __ _ __ __ __ _ | |_ ___
864# | ___/ | '__| | | \ \ / / / _` | | __| / _ \
865# | | | | | | \ V / | (_| | \ |_ | __/
866# |_| |_| |_| \_/ \__,_| \__| \___|
867*/
868
869
870
871
872
873
874
876{
877 const size_t len = strlen(prefix);
878
879 // if filename does not began with prefix, return 0
880 if (strncmp(prefix, fileName, len) != 0) {
881 return 0;
882 }
883
884 // we point on the first char after prefix
885 const char *suffix = &(fileName[len]);
886
887 // we test that suffix is valid (at least begin with digit)
888 if (!isdigit((int) suffix[0])) {
889 // DebugTrace ("DBG> suffix = %s", suffix);
890 return 0;
891 }
892
893 return (int32_t) atoi(suffix);
894}
895
896
897#ifdef SDLOG_NEED_QUEUE
898static void cleanQueue(const bool allQueue)
899{
900 if (allQueue == false) {
901 do {
902 struct tlsf_stat_t stat;
904 const size_t freeRam = stat.mfree;
905 chSysLock();
906 const bool queue_full = (chMBGetFreeCountI(&messagesQueue.mb) <= 0);
907 chSysUnlock();
908 // DebugTrace ("sdLogCloseLog freeRam=%d queue_full=%d", freeRam, queue_full);
909 if ((freeRam < 200) || (queue_full == true)) {
911 } else {
912 break;
913 }
914 } while (true);
915 } else {
917 }
918}
919
920static void removeFromQueue(const size_t nbMsgToRFemove)
921{
922 /* struct tlsf_stat_t stat; */
923
924 /* tlsf_stat_r (&HEAP_DEFAULT, &stat); */
925 /* size_t freeRam = stat.mfree; */
926 /* chSysLock(); */
927 /* size_t queueBuckets = chMBGetFreeCountI(&messagesQueue.mb); */
928 /* chSysUnlock(); */
929
930 /* DebugTrace ("Before removeFromQueue (%d) : ram=%d buck=%d", nbMsgToRFemove, freeRam, queueBuckets); */
931
932 LogMessage *lm = NULL;
933 for (size_t i = 0; i < nbMsgToRFemove; i++) {
935 if (retLen < 0) {
936 break;
937 }
939 }
940
941 /* tlsf_stat_r (&HEAP_DEFAULT, &stat); */
942 /* freeRam = stat.mfree; */
943 /* chSysLock(); */
944 /* queueBuckets = chMBGetFreeCountI(&messagesQueue.mb); */
945 /* chSysUnlock(); */
946
947 /* DebugTrace ("After removeFromQueue (%d) : ram=%d buck=%d", nbMsgToRFemove, freeRam, queueBuckets); */
948}
949
950
951static void thdSdLog(void *arg)
952{
953 (void) arg;
954 struct PerfBuffer {
955 // each element of buffer should be word aligned for sdio efficient write
957 uint16_t size;
958 } ;
959
960 UINT bw;
964 while (true) {
965 LogMessage *lm = NULL;
966 const int32_t retLen = (int32_t)(msgqueue_pop(&messagesQueue, (void **) &lm));
967 if (retLen > 0) {
968 FIL *fo = &fileDes[lm->op.fd].fil;
969 uint8_t *const perfBuffer = perfBuffers[lm->op.fd].buffer;
970
971 switch (lm->op.fcntl) {
972
973 case FCNTL_FLUSH:
974 case FCNTL_CLOSE: {
975 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
976 if (fileDes[lm->op.fd].inUse) {
977 if (curBufFill) {
980 perfBuffers[lm->op.fd].size = 0;
981 }
982 if (lm->op.fcntl == FCNTL_FLUSH) {
983 f_sync(fo);
984 } else { // close
985 if (fileDes[lm->op.fd].tagAtClose) {
986 f_write(fo, "\r\nEND_OF_LOG\r\n", 14, &bw);
988 }
989 f_close(fo);
990 fileDes[lm->op.fd].inUse = false; // store that file is closed
991 }
992 }
993 }
994 break;
995
996 case FCNTL_EXIT:
997 tlsf_free_r(&HEAP_DEFAULT, lm); // to avoid a memory leak
999 break; /* To exit from thread when asked : chThdTerminate
1000 then send special message with FCNTL_EXIT */
1001
1002
1003 case FCNTL_WRITE: {
1004 const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
1005 if (fileDes[lm->op.fd].inUse) {
1006 const int32_t messLen = retLen - (int32_t)(sizeof(LogMessage));
1008 // the buffer can accept this message
1009 memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(messLen));
1010 perfBuffers[lm->op.fd].size = (uint16_t)((perfBuffers[lm->op.fd].size) + messLen);
1011 } else {
1012 // fill the buffer
1014 memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(stayLen));
1016 nbBytesWritten += bw;
1017 // if there an autoflush period specified, flush to the mass storage media
1018 // if timer has expired and rearm.
1019 if (fileDes[lm->op.fd].autoFlushPeriod) {
1021 if ((now - fileDes[lm->op.fd].lastFlushTs) >
1022 (fileDes[lm->op.fd].autoFlushPeriod * CH_CFG_ST_FREQUENCY)) {
1023 f_sync(fo);
1024 fileDes[lm->op.fd].lastFlushTs = now;
1025 }
1026 }
1027 if (rc) {
1028 //chThdExit(storageStatus = SDLOG_FATFS_ERROR);
1030 } else if (bw != SDLOG_WRITE_BUFFER_SIZE) {
1032 }
1033
1035 perfBuffers[lm->op.fd].size = (uint16_t)(messLen - stayLen); // curBufFill
1036 }
1037 }
1038 }
1039 }
1041 } else {
1043 }
1044 }
1045}
1046
1047static size_t logMessageLen(const LogMessage *lm)
1048{
1049 return sizeof(LogMessage) + strnlen(lm->mess, SDLOG_MAX_MESSAGE_LEN);
1050}
1051
1052static size_t logRawLen(const size_t len)
1053{
1054 return sizeof(LogMessage) + len;
1055}
1056
1058{
1059 // if there is a free slot in fileDes, use it
1060 // else, if all slots are buzy, maximum open files limit
1061 // is reach.
1062 for (FileDes i = 0; i < SDLOG_NUM_FILES; i++) {
1063 if (fileDes[i].inUse == false) {
1064 *fd = i;
1065 fileDes[i].inUse = true;
1066 return SDLOG_OK;
1067 }
1068 }
1069 return SDLOG_FDFULL;
1070}
1071
1073{
1074 return nbBytesWritten;
1075}
1076
1078{
1079 return storageStatus;
1080}
1081
1082
1083#endif
static uint8_t status
static int fo
Definition chdk_pipe.c:24
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
static const float offset[]
#define FF_MAX_LFN
Definition ffconf.h:121
void chvsnprintf(char *buffer, size_t size, const char *fmt, va_list ap)
Definition printf.c:372
void chsnprintf(char *buffer, size_t size, const char *fmt,...)
Definition printf.c:377
#define CH_CFG_ST_FREQUENCY
System tick frequency.
Definition chconf.h:75
uint16_t foo
Definition main_demo5.c:58
#define SDLOG_MAX_MESSAGE_LEN
Definition mcuconf_h7.h:675
#define SDLOG_QUEUE_BUCKETS
Definition mcuconf_h7.h:674
#define SDLOG_NUM_FILES
Definition mcuconf_h7.h:676
#define true
Definition microrl.h:6
int32_t msgqueue_pop_timeout(MsgQueue *que, void **msgPtr, const systime_t timout)
receive message specifying timeout
Definition msg_queue.c:139
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
Definition msg_queue.c:69
int32_t msgqueue_pop(MsgQueue *que, void **msgPtr)
wait then receive message
Definition msg_queue.c:134
void msgqueue_init(MsgQueue *que, tlsf_memory_heap_t *heap, msg_t *mb_buf, const cnt_t mb_size)
initialise MsgQueue
Definition msg_queue.c:42
int32_t msgqueue_copy_send(MsgQueue *que, const void *msg, const uint16_t msgLen, const MsgQueueUrgency urgency)
send a buffer NOT previously allocated
Definition msg_queue.c:127
@ MsgQueue_REGULAR
Definition msg_queue.h:47
@ MsgQueue_OUT_OF_BAND
Definition msg_queue.h:47
Mini printf-like functionality.
Specific RAM section for DMA usage on F7.
#define IN_STD_SECTION_CLEAR(var)
Definition ram_arch.h:78
SdioError sdLogFinish(void)
unmount filesystem
Definition sdLog.c:285
SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
remove spurious log file left on sd
Definition sdLog.c:815
static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
Definition sdLog.c:875
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
Definition sdLog.c:754
SdioError sdLogInit(uint32_t *freeSpaceInKo)
initialise sdLog
Definition sdLog.c:225
#define MIN(x, y)
Definition sdLog.c:39
static SdioError flushWriteByteBuffer(const FileDes fd)
#define MAX(x, y)
Definition sdLog.c:42
static IN_SDMMC_DMA_SECTION(FATFS fatfs)
#define SDLOG_WRITE_BUFFER_SIZE
Definition sdLog.c:71
struct _SdLogBuffer SdLogBuffer
Definition sdLog.h:127
#define NUMBERFMF
Definition sdLog.h:36
#define NUMBERMAX
Definition sdLog.h:35
int8_t FileDes
Definition sdLog.h:128
SdioError
Definition sdLog.h:111
@ SDLOG_NOCARD
Definition sdLog.h:113
@ SDLOG_QUEUEFULL
Definition sdLog.h:118
@ SDLOG_LOGNUM_ERROR
Definition sdLog.h:123
@ SDLOG_FATFS_ERROR
Definition sdLog.h:114
@ SDLOG_FSFULL
Definition sdLog.h:116
@ SDLOG_WAS_LAUNCHED
Definition sdLog.h:124
@ SDLOG_OK
Definition sdLog.h:112
@ SDLOG_FDFULL
Definition sdLog.h:117
@ SDLOG_MEMFULL
Definition sdLog.h:119
@ SDLOG_FATFS_NOENT
Definition sdLog.h:115
@ SDLOG_NOTHREAD
Definition sdLog.h:120
@ SDLOG_INTERNAL_ERROR
Definition sdLog.h:121
@ SDLOG_CANNOT_EXPAND
Definition sdLog.h:122
arch independent SDIO API
bool sdio_connect(SDCDriver *sdc)
Connect a SD card on SDIO peripheral.
Definition sdio_arch.c:48
bool sdio_disconnect(SDCDriver *sdc)
Disconnect a SD card on SDIO peripheral.
Definition sdio_arch.c:73
int fd
Definition serial.c:26
static const float dir[]
#define FALSE
Definition std.h:5
void tlsf_free_r(tlsf_memory_heap_t *heap, void *ptr)
void * tlsf_malloc_r(tlsf_memory_heap_t *heap, size_t bytes)
void tlsf_stat_r(tlsf_memory_heap_t *heap, struct tlsf_stat_t *stat)
void * tlsf_realloc_r(tlsf_memory_heap_t *heap, void *ptr, size_t bytes)
#define HEAP_DEFAULT
uint32_t DWORD
Definition usb_msd.c:133
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.