Paparazzi UAS  v6.2_unstable
Paparazzi is a free software Unmanned Aircraft System.
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 
113 
114 
115 static msg_t IN_STD_SECTION_CLEAR(queMbBuffer[SDLOG_QUEUE_BUCKETS]);
116 static MsgQueue messagesQueue;
117 
118 #define WRITE_BYTE_CACHE_SIZE 15 // limit overhead :
119 // malloc (15+1) occupies 20bytes
120 typedef struct {
121  uint8_t fcntl: 2;
122  uint8_t fd: 6;
123 } FileOp;
124 
125 struct LogMessage {
126  FileOp op;
127  char mess[0];
128 };
129 
130 struct FilePoolUnit {
131  FIL fil;
132  uint32_t autoFlushPeriod;
133  systime_t lastFlushTs;
134  bool inUse;
135  bool tagAtClose;
136  // optimise write byte by caching at send level now that we are based upon tlsf where
137  // allocation granularity is 16 bytes
138  LogMessage *writeByteCache;
139  uint8_t writeByteSeek;
140 };
141 
142 static struct FilePoolUnit IN_DMA_SECTION(fileDes[SDLOG_NUM_FILES]) = {
143  [0 ... SDLOG_NUM_FILES - 1] = {
144  .fil = {{0}}, .inUse = false, .tagAtClose = false,
145  .writeByteCache = NULL, .writeByteSeek = 0
146  }
147 };
148 
149 static volatile size_t nbBytesWritten = 0;
150 static SdioError storageStatus = SDLOG_OK;
151 
152 typedef enum {
153  FCNTL_WRITE = 0b00,
154  FCNTL_FLUSH = 0b01,
155  FCNTL_CLOSE = 0b10,
156  FCNTL_EXIT = 0b11
157 } FileFcntl;
158 
159 struct _SdLogBuffer {
160  LogMessage *lm;
161  size_t len;
163 } ;
164 
165 
166 #define LOG_MESSAGE_PREBUF_LEN (SDLOG_MAX_MESSAGE_LEN+sizeof(LogMessage))
167 #endif // SDLOG_NEED_QUEUE
168 
169 /* File system object */
170 static IN_DMA_SECTION(FATFS fatfs);
171 
172 #ifdef SDLOG_NEED_QUEUE
173 static size_t logMessageLen(const LogMessage *lm);
174 static size_t logRawLen(const size_t len);
175 static SdioError sdLoglaunchThread(void);
176 static SdioError sdLogStopThread(void);
177 static thread_t *sdLogThd = NULL;
178 static SdioError getNextFIL(FileDes *fd);
179 static void removeFromQueue(const size_t nbMsgToRFemov);
180 static void cleanQueue(const bool allQueue);
181 static SdioError sdLogExpandLogFile(const FileDes fileObject, const size_t sizeInMo,
182  const bool preallocate);
183 
184 static void thdSdLog(void *arg) ;
185 
186 #endif // SDLOG_NEED_QUEUE
187 
188 static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName) ;
189 static inline SdioError flushWriteByteBuffer(const FileDes fd);
190 
191 SdioError sdLogInit(uint32_t *freeSpaceInKo)
192 {
193  DWORD clusters = 0;
194  FATFS *fsp = NULL;
195  nbBytesWritten = 0;
196 
197  // if init is already done, return ERROR
198  if (sdLogThd != NULL) {
199  *freeSpaceInKo = 0;
200  return storageStatus = SDLOG_WAS_LAUNCHED;
201  }
202 
203 #ifdef SDLOG_NEED_QUEUE
204  msgqueue_init(&messagesQueue, &HEAP_DEFAULT, queMbBuffer, SDLOG_QUEUE_BUCKETS);
205 #endif
206 
207  if (!sdc_lld_is_card_inserted(NULL)) {
208  return storageStatus = SDLOG_NOCARD;
209  }
210 
211 
212  sdio_connect();
213  chThdSleepMilliseconds(10);
214  sdio_disconnect();
215 
216  if (sdio_connect() == FALSE) {
217  return storageStatus = SDLOG_NOCARD;
218  }
219 
220 #if FFCONF_DEF < 8000
221  FRESULT rc = f_mount(0, &fatfs);
222 #else
223  FRESULT rc = f_mount(&fatfs, "/", 1);
224 #endif
225 
226  if (rc != FR_OK) {
227  return storageStatus = SDLOG_FATFS_ERROR;
228  }
229 
230  if (freeSpaceInKo != NULL) {
231  f_getfree("/", &clusters, &fsp);
232  *freeSpaceInKo = clusters * (uint32_t)fatfs.csize / 2;
233  }
234 
235 #ifdef SDLOG_NEED_QUEUE
236  for (uint8_t i = 0; i < SDLOG_NUM_FILES; i++) {
237  fileDes[i].inUse = fileDes[i].tagAtClose = false;
238  fileDes[i].writeByteCache = NULL;
239  fileDes[i].writeByteSeek = 0;
240  }
241 
242  storageStatus = sdLoglaunchThread();
243 #else
244  storageStatus = SDLOG_OK;
245 #endif
246  return storageStatus;
247 
248 }
249 
250 
252 {
253 #if FFCONF_DEF < 8000
254  FRESULT rc = f_mount(0, NULL);
255 #else
256  FRESULT rc = f_mount(NULL, "", 0);
257 #endif
258  if (rc != FR_OK) {
259  return storageStatus = SDLOG_FATFS_ERROR;
260  }
261 
262  // if we mount, unmount, don't disconnect sdio
263  /* if (sdio_disconnect () == FALSE) */
264  /* return SDLOG_NOCARD; */
265 
266  return storageStatus = SDLOG_OK;
267 }
268 
269 
270 
271 #ifdef SDLOG_NEED_QUEUE
272 SdioError sdLogOpenLog(FileDes *fd, const char *directoryName, const char *prefix,
273  const uint32_t autoFlushPeriod, const bool appendTagAtClose,
274  const size_t sizeInMo, const bool preallocate, char *fileName, const size_t nameLength)
275 {
276  FRESULT rc; /* fatfs result code */
277  SdioError sde = SDLOG_OK; /* sdio result code */
278  //DIR dir; /* Directory object */
279  //FILINFO fno; /* File information object */
280 
281  /* local file descriptor
282  using fd is a bad idea since fd is set before fatfs objets are coherents
283  in a multithreaded application where sdLogXXX are done before sdLogWriteLog is done
284  we can have a race condition. setting fd only when fatfs files are opened resolve the problem
285  */
286  FileDes ldf;
287 
288  sde = getNextFIL(&ldf);
289  if (sde != SDLOG_OK) {
290  return storageStatus = sde;
291  }
292 
293  sde = getFileName(prefix, directoryName, fileName, nameLength, +1);
294  if (sde != SDLOG_OK) {
295  // sd card is not inserted, so logging task can be deleted
296  return storageStatus = SDLOG_FATFS_ERROR;
297  }
298 
299 
300  rc = f_open(&fileDes[ldf].fil, fileName, FA_WRITE | FA_CREATE_ALWAYS);
301  if (rc) {
302  fileDes[ldf].inUse = false;
303  return storageStatus = SDLOG_FATFS_ERROR;
304  } else {
305  fileDes[ldf].tagAtClose = appendTagAtClose;
306  fileDes[ldf].autoFlushPeriod = autoFlushPeriod;
307  fileDes[ldf].lastFlushTs = 0;
308  sde = sdLogExpandLogFile(ldf, sizeInMo, preallocate);
309  }
310 
311  *fd = ldf;
312  return storageStatus = sde;
313 }
314 
315 SdioError sdLogCloseAllLogs(bool flush)
316 {
317  FRESULT rc = 0; /* Result code */
318 
319  // do not flush what is in ram, close as soon as possible
320  if (flush == false) {
321  UINT bw;
322  // stop worker thread then close file
323  cleanQueue(true);
324  sdLogStopThread();
325 
326  for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
327  if (fileDes[fd].inUse) {
328  FIL *fo = &fileDes[fd].fil;
329  if (fileDes[fd].tagAtClose) {
330  f_write(fo, "\r\nEND_OF_LOG\r\n", 14, &bw);
331  nbBytesWritten += bw;
332  }
333  FRESULT trc = f_close(fo);
334  fileDes[fd].inUse = false;
335  if (!rc) {
336  rc = trc;
337  }
338  }
339  }
340 
341  if (rc) {
342  return storageStatus = SDLOG_FATFS_ERROR;
343  }
344 
345  // flush ram buffer then close
346  } else { // flush == true
347  if (sdLogThd == NULL) {
348  // something goes wrong, log thread is no more working
349  return storageStatus = SDLOG_NOTHREAD;
350  }
351 
352  // queue flush + close order, then stop worker thread
353  for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
354  if (fileDes[fd].inUse) {
356  sdLogCloseLog(fd);
357  }
358  }
359 
360  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
361  if (lm == NULL) {
362  return storageStatus = SDLOG_MEMFULL;
363  }
364 
365  lm->op.fcntl = FCNTL_EXIT;
366 
367  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
368  return storageStatus = SDLOG_QUEUEFULL;
369  } else {
370  chThdWait(sdLogThd);
371  sdLogThd = NULL;
372  }
373 
374  }
375  return storageStatus = SDLOG_OK;
376 }
377 
378 SdioError sdLogFlushAllLogs(void)
379 {
381  if (sdLogThd == NULL) {
382  // something goes wrong, log thread is no more working
383  return storageStatus = SDLOG_NOTHREAD;
384  }
385 
386  // queue flush + close order, then stop worker thread
387  for (FileDes fd = 0; fd < SDLOG_NUM_FILES; fd++) {
388  if (fileDes[fd].inUse) {
389  status = sdLogFlushLog(fd);
390  if (status != SDLOG_OK) {
391  break;
392  }
393  }
394  }
395 
396  return storageStatus = status;
397 }
398 
399 
400 #define FD_CHECK(fd) if ((fd < 0) || (fd >= SDLOG_NUM_FILES) \
401  || (fileDes[fd].inUse == false)) \
402  return SDLOG_FATFS_ERROR
403 
404 
405 SdioError sdLogExpandLogFile(const FileDes fd, const size_t sizeInMo,
406  const bool preallocate)
407 {
408  FD_CHECK(fd);
409 
410  // expand with opt=1 : pre allocate file now
411  const FRESULT rc = f_expand(&fileDes[fd].fil, sizeInMo * 1024 * 1024, preallocate);
412  return (rc == FR_OK) ? SDLOG_OK : SDLOG_CANNOT_EXPAND;
413 }
414 
415 SdioError sdLogWriteLog(const FileDes fd, const char *fmt, ...)
416 {
417  FD_CHECK(fd);
418 
420  storageStatus = status;
421  if (status != SDLOG_OK) {
422  return status;
423  }
424 
425  va_list ap;
426  va_start(ap, fmt);
427 
428  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, LOG_MESSAGE_PREBUF_LEN);
429  if (lm == NULL) {
430  va_end(ap);
431  return storageStatus = SDLOG_MEMFULL;
432  }
433 
434  lm->op.fcntl = FCNTL_WRITE;
435  lm->op.fd = fd & 0x1f;
436 
437  chvsnprintf(lm->mess, SDLOG_MAX_MESSAGE_LEN - 1, fmt, ap);
438  lm->mess[SDLOG_MAX_MESSAGE_LEN - 1] = 0;
439  va_end(ap);
440 
441  const size_t msgLen = logMessageLen(lm);
442  lm = tlsf_realloc_r(&HEAP_DEFAULT, lm, msgLen);
443  if (lm == NULL) {
444  return storageStatus = SDLOG_MEMFULL;
445  }
446 
447  if (msgqueue_send(&messagesQueue, lm, msgLen, MsgQueue_REGULAR) < 0) {
448  return storageStatus = SDLOG_QUEUEFULL;
449  }
450 
451  return SDLOG_OK;
452 }
453 
454 SdioError sdLogFlushLog(const FileDes fd)
455 {
456  FD_CHECK(fd);
457 
459  storageStatus = status;
460  if (status != SDLOG_OK) {
461  return status;
462  }
463 
464  // give room to send a flush order if the queue is full
465  cleanQueue(false);
466 
467  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
468  if (lm == NULL) {
469  return storageStatus = SDLOG_MEMFULL;
470  }
471 
472  lm->op.fcntl = FCNTL_FLUSH;
473  lm->op.fd = fd & 0x1f;
474 
475  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
476  return storageStatus = SDLOG_QUEUEFULL;
477  }
478 
479  return SDLOG_OK;
480 }
481 
482 SdioError sdLogCloseLog(const FileDes fd)
483 {
484  FD_CHECK(fd);
485 
486  cleanQueue(false);
487  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
488  if (lm == NULL) {
489  return storageStatus = SDLOG_MEMFULL;
490  }
491 
492  lm->op.fcntl = FCNTL_CLOSE;
493  lm->op.fd = fd & 0x1f;
494 
495  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
496  return storageStatus = SDLOG_QUEUEFULL;
497  }
498 
499  return storageStatus = SDLOG_OK;
500 }
501 
502 
503 
504 
505 
506 static inline SdioError flushWriteByteBuffer(const FileDes fd)
507 {
508  FD_CHECK(fd);
509 
510  if (unlikely(fileDes[fd].writeByteCache != NULL)) {
511  if (msgqueue_send(&messagesQueue, fileDes[fd].writeByteCache,
512  sizeof(LogMessage) + fileDes[fd].writeByteSeek,
513  MsgQueue_REGULAR) < 0) {
514  return storageStatus = SDLOG_QUEUEFULL;
515  }
516  fileDes[fd].writeByteCache = NULL;
517  }
518  return storageStatus = SDLOG_OK;
519 }
520 
521 SdioError sdLogWriteRaw(const FileDes fd, const uint8_t *buffer, const size_t len)
522 {
523  FD_CHECK(fd);
524 
526  storageStatus = status;
527  if (status != SDLOG_OK) {
528  return status;
529  }
530 
531  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
532  if (lm == NULL) {
533  return storageStatus = SDLOG_MEMFULL;
534  }
535 
536  lm->op.fcntl = FCNTL_WRITE;
537  lm->op.fd = fd & 0x1f;
538  memcpy(lm->mess, buffer, len);
539 
540  if (msgqueue_send(&messagesQueue, lm, logRawLen(len), MsgQueue_REGULAR) < 0) {
541  return storageStatus = SDLOG_QUEUEFULL;
542  }
543 
544  return SDLOG_OK;
545 }
546 
547 SdioError sdLogAllocSDB(SdLogBuffer **sdb, const size_t len)
548 {
549  *sdb = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
550  if (*sdb == NULL) {
551  return storageStatus = SDLOG_MEMFULL;
552  }
553 
554  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
555  if (lm == NULL) {
556  tlsf_free_r(&HEAP_DEFAULT, *sdb);
557  return storageStatus = SDLOG_MEMFULL;
558  }
559 
560  (*sdb)->lm = lm;
561  (*sdb)->len = len;
562  (*sdb)->offset = 0;
563  return storageStatus = SDLOG_OK;
564 }
565 
566 char *sdLogGetBufferFromSDB(SdLogBuffer *sdb)
567 {
568  return sdb->lm->mess + sdb->offset;
569 }
570 
571 bool sdLogSeekBufferFromSDB(SdLogBuffer *sdb, uint32_t offset)
572 {
573  if ((sdb->offset + offset) < sdb->len) {
574  sdb->offset += offset;
575  return true;
576  } else {
577  return false;
578  }
579 }
580 
581 size_t sdLogGetBufferLenFromSDB(SdLogBuffer *sdb)
582 {
583  return sdb->len - sdb->offset;
584 }
585 
586 SdioError sdLogWriteSDB(const FileDes fd, SdLogBuffer *sdb)
587 {
589 
590  if ((fd < 0) || (fd >= SDLOG_NUM_FILES) || (fileDes[fd].inUse == false)) {
592  goto fail;
593  }
594 
596  if (status != SDLOG_OK) {
597  goto fail;
598  }
599 
600 
601  sdb->lm->op.fcntl = FCNTL_WRITE;
602  sdb->lm->op.fd = fd & 0x1f;
603 
604  if (msgqueue_send(&messagesQueue, sdb->lm, logRawLen(sdb->len), MsgQueue_REGULAR) < 0) {
605  // msgqueue_send take care of freeing lm memory even in case of failure
606  // just need to free sdb memory
608  }
609 
610  goto exit;
611 
612 fail:
613  tlsf_free_r(&HEAP_DEFAULT, sdb->lm);
614 
615 exit:
616  tlsf_free_r(&HEAP_DEFAULT, sdb);
617  return storageStatus = status;
618 }
619 
620 
621 
622 
623 SdioError sdLogWriteByte(const FileDes fd, const uint8_t value)
624 {
625  FD_CHECK(fd);
626  LogMessage *lm;
627 
628  if (fileDes[fd].writeByteCache == NULL) {
629  lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage) + WRITE_BYTE_CACHE_SIZE);
630  if (lm == NULL) {
631  return storageStatus = SDLOG_MEMFULL;
632  }
633 
634  lm->op.fcntl = FCNTL_WRITE;
635  lm->op.fd = fd & 0x1f;
636 
637  fileDes[fd].writeByteCache = lm;
638  fileDes[fd].writeByteSeek = 0;
639  } else {
640  lm = fileDes[fd].writeByteCache;
641  }
642 
643  lm->mess[fileDes[fd].writeByteSeek++] = value;
644 
645  if (fileDes[fd].writeByteSeek == WRITE_BYTE_CACHE_SIZE) {
647  // message is not sent so allocated buffer will not be released by receiver side
648  // instead of freeing buffer, we just reset cache seek.
649  if (status == SDLOG_QUEUEFULL) {
650  fileDes[fd].writeByteSeek = 0;
651  return storageStatus = SDLOG_QUEUEFULL;
652  }
653  }
654  return storageStatus = SDLOG_OK;
655 }
656 
657 /*
658  if fatfs use stack for working buffers, stack size should be reserved accordingly
659  */
660 #define WA_LOG_BASE_SIZE 1024
661 #if FF_USE_LFN == 2
662 #if FF_FS_EXFAT
663 static IN_DMA_SECTION_NOINIT(THD_WORKING_AREA(waThdSdLog, WA_LOG_BASE_SIZE+((FF_MAX_LFN+1)*2)+(19*32)));
664 #else
665 static IN_DMA_SECTION_NOINIT(THD_WORKING_AREA(waThdSdLog, WA_LOG_BASE_SIZE+((FF_MAX_LFN+1)*2)));
666 #endif
667 #else
668 static THD_WORKING_AREA(waThdSdLog, WA_LOG_BASE_SIZE);
669 #endif
670 
671 SdioError sdLoglaunchThread ()
672 {
673  chThdSleepMilliseconds(100);
674 
675  sdLogThd = chThdCreateStatic(waThdSdLog, sizeof(waThdSdLog),
676  NORMALPRIO + 1, thdSdLog, NULL);
677  if (sdLogThd == NULL) {
678  return storageStatus = SDLOG_INTERNAL_ERROR;
679  } else {
680  return storageStatus = SDLOG_OK;
681  }
682 }
683 
684 SdioError sdLogStopThread(void)
685 {
686  SdioError retVal = SDLOG_OK;
687 
688  storageStatus = retVal;
689  if (sdLogThd == NULL) {
690  return storageStatus = SDLOG_NOTHREAD;
691  }
692 
693  LogMessage lm;
694 
695  /* // ask for closing (after flushing) all opened files */
696  /* for (uint8_t i=0; i<SDLOG_NUM_FILES; i++) { */
697  /* if (fileDes[i].inUse) { */
698  /* flushWriteByteBuffer (i); */
699  /* lm.op.fcntl = FCNTL_CLOSE; */
700  /* lm.op.fd = i & 0x1f; */
701  /* if (msgqueue_copy_send (&messagesQueue, &lm, sizeof(LogMessage), MsgQueue_OUT_OF_BAND) < 0) { */
702  /* retVal= SDLOG_QUEUEFULL; */
703  /* } */
704  /* } */
705  /* } */
706 
707  lm.op.fcntl = FCNTL_EXIT;
708  if (msgqueue_copy_send(&messagesQueue, &lm, sizeof(LogMessage), MsgQueue_OUT_OF_BAND) < 0) {
709  retVal = SDLOG_QUEUEFULL;
710  }
711 
712  chThdWait(sdLogThd);
713  sdLogThd = NULL;
714  return storageStatus = retVal;
715 }
716 #endif
717 
718 
719 SdioError getFileName(const char *prefix, const char *directoryName,
720  char *nextFileName, const size_t nameLength, const int indexOffset)
721 {
722  DIR dir; /* Directory object */
723  FRESULT rc; /* Result code */
724  FILINFO fno; /* File information object */
725  int32_t fileIndex ;
726  int32_t maxCurrentIndex = 0;
727 
728 
729  const size_t directoryNameLen = MIN(strlen(directoryName), 128);
730  const size_t slashDirNameLen = directoryNameLen + 2;
731  char slashDirName[slashDirNameLen];
732  strlcpy(slashDirName, "/", slashDirNameLen);
733  strlcat(slashDirName, directoryName, slashDirNameLen);
734 
735  rc = f_opendir(&dir, directoryName);
736  if (rc != FR_OK) {
737  rc = f_mkdir(slashDirName);
738  if (rc != FR_OK) {
739  return storageStatus = SDLOG_FATFS_ERROR;
740  }
741  rc = f_opendir(&dir, directoryName);
742  if (rc != FR_OK) {
743  return storageStatus = SDLOG_FATFS_ERROR;
744  }
745  }
746 
747  for (;;) {
748  rc = f_readdir(&dir, &fno); /* Read a directory item */
749  if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
750 
751 
752  if (fno.fname[0] == '.') { continue; }
753 
754  if (!(fno.fattrib & AM_DIR)) {
755  // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
756  fileIndex = uiGetIndexOfLogFile(prefix, fno.fname);
757  maxCurrentIndex = MAX(maxCurrentIndex, fileIndex);
758  }
759  }
760  if (rc) {
761  return storageStatus = SDLOG_FATFS_ERROR;
762  }
763 
764  rc = f_closedir(&dir);
765  if (rc) {
766  return storageStatus = SDLOG_FATFS_ERROR;
767  }
768 
769  if (maxCurrentIndex < NUMBERMAX) {
770  chsnprintf(nextFileName, nameLength, NUMBERFMF,
771  directoryName, prefix, maxCurrentIndex + indexOffset);
772  return storageStatus = SDLOG_OK;
773  } else {
774  chsnprintf(nextFileName, nameLength, "%s\\%s%.ERR",
775  directoryName, prefix);
776  return storageStatus = SDLOG_LOGNUM_ERROR;
777  }
778 }
779 
780 SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
781 {
782  DIR dir; /* Directory object */
783  FRESULT rc; /* Result code */
784  FILINFO fno; /* File information object */
785 
786 
787  rc = f_opendir(&dir, directoryName);
788  if (rc != FR_OK) {
789  return storageStatus = SDLOG_FATFS_NOENT;
790  }
791 
792  for (;;) {
793  rc = f_readdir(&dir, &fno); /* Read a directory item */
794  if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
795 
796  if (fno.fname[0] == '.') { continue; }
797 
798  if (!(fno.fattrib & AM_DIR)) {
799  // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
800  if ((strncmp(fno.fname, prefix, strlen(prefix)) == 0) && (fno.fsize <= sizeConsideredEmpty)) {
801  char absPathName[128];
802  strlcpy(absPathName, directoryName, sizeof(absPathName));
803  strlcat(absPathName, "/", sizeof(absPathName));
804  strlcat(absPathName, fno.fname, sizeof(absPathName));
805  rc = f_unlink(absPathName);
806  if (rc) {
807  break;
808  }
809  }
810  }
811  }
812 
813  if (rc) {
814  return storageStatus = SDLOG_FATFS_ERROR;
815  }
816 
817  rc = f_closedir(&dir);
818  if (rc) {
819  return storageStatus = SDLOG_FATFS_ERROR;
820  }
821 
822  return storageStatus = SDLOG_OK;
823 }
824 
825 /*
826 # _____ _ _
827 # | __ \ (_) | |
828 # | |__) | _ __ _ __ __ __ _ | |_ ___
829 # | ___/ | '__| | | \ \ / / / _` | | __| / _ \
830 # | | | | | | \ V / | (_| | \ |_ | __/
831 # |_| |_| |_| \_/ \__,_| \__| \___|
832 */
833 
834 
835 
836 
837 
838 
839 
840 int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
841 {
842  const size_t len = strlen(prefix);
843 
844  // if filename does not began with prefix, return 0
845  if (strncmp(prefix, fileName, len) != 0) {
846  return 0;
847  }
848 
849  // we point on the first char after prefix
850  const char *suffix = &(fileName[len]);
851 
852  // we test that suffix is valid (at least begin with digit)
853  if (!isdigit((int) suffix[0])) {
854  // DebugTrace ("DBG> suffix = %s", suffix);
855  return 0;
856  }
857 
858  return (int32_t) atoi(suffix);
859 }
860 
861 
862 #ifdef SDLOG_NEED_QUEUE
863 static void cleanQueue(const bool allQueue)
864 {
865  if (allQueue == false) {
866  do {
867  struct tlsf_stat_t stat;
868  tlsf_stat_r(&HEAP_DEFAULT, &stat);
869  const size_t freeRam = stat.mfree;
870  chSysLock();
871  const bool queue_full = (chMBGetFreeCountI(&messagesQueue.mb) <= 0);
872  chSysUnlock();
873  // DebugTrace ("sdLogCloseLog freeRam=%d queue_full=%d", freeRam, queue_full);
874  if ((freeRam < 200) || (queue_full == true)) {
875  removeFromQueue(1);
876  } else {
877  break;
878  }
879  } while (true);
880  } else {
881  removeFromQueue(SDLOG_QUEUE_BUCKETS);
882  }
883 }
884 
885 static void removeFromQueue(const size_t nbMsgToRFemove)
886 {
887  /* struct tlsf_stat_t stat; */
888 
889  /* tlsf_stat_r (&HEAP_DEFAULT, &stat); */
890  /* size_t freeRam = stat.mfree; */
891  /* chSysLock(); */
892  /* size_t queueBuckets = chMBGetFreeCountI(&messagesQueue.mb); */
893  /* chSysUnlock(); */
894 
895  /* DebugTrace ("Before removeFromQueue (%d) : ram=%d buck=%d", nbMsgToRFemove, freeRam, queueBuckets); */
896 
897  LogMessage *lm = NULL;
898  for (size_t i = 0; i < nbMsgToRFemove; i++) {
899  const int32_t retLen = (int32_t)(msgqueue_pop_timeout(&messagesQueue, (void **) &lm, TIME_IMMEDIATE));
900  if (retLen < 0) {
901  break;
902  }
904  }
905 
906  /* tlsf_stat_r (&HEAP_DEFAULT, &stat); */
907  /* freeRam = stat.mfree; */
908  /* chSysLock(); */
909  /* queueBuckets = chMBGetFreeCountI(&messagesQueue.mb); */
910  /* chSysUnlock(); */
911 
912  /* DebugTrace ("After removeFromQueue (%d) : ram=%d buck=%d", nbMsgToRFemove, freeRam, queueBuckets); */
913 }
914 
915 
916 static void thdSdLog(void *arg)
917 {
918  (void) arg;
919  struct PerfBuffer {
920  // each element of buffer should be word aligned for sdio efficient write
921  ALIGNED_VAR(4) uint8_t buffer[SDLOG_WRITE_BUFFER_SIZE] ;
922  uint16_t size;
923  } ;
924 
925  UINT bw;
926  static IN_DMA_SECTION_CLEAR(struct PerfBuffer perfBuffers[SDLOG_NUM_FILES]);
927  storageStatus = SDLOG_OK;
928  chRegSetThreadName("thdSdLog");
929  while (true) {
930  LogMessage *lm = NULL;
931  const int32_t retLen = (int32_t)(msgqueue_pop(&messagesQueue, (void **) &lm));
932  if (retLen > 0) {
933  FIL *fo = &fileDes[lm->op.fd].fil;
934  uint8_t *const perfBuffer = perfBuffers[lm->op.fd].buffer;
935 
936  switch (lm->op.fcntl) {
937 
938  case FCNTL_FLUSH:
939  case FCNTL_CLOSE: {
940  const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
941  if (fileDes[lm->op.fd].inUse) {
942  if (curBufFill) {
943  f_write(fo, perfBuffer, curBufFill, &bw);
944  nbBytesWritten += bw;
945  perfBuffers[lm->op.fd].size = 0;
946  }
947  if (lm->op.fcntl == FCNTL_FLUSH) {
948  f_sync(fo);
949  } else { // close
950  if (fileDes[lm->op.fd].tagAtClose) {
951  f_write(fo, "\r\nEND_OF_LOG\r\n", 14, &bw);
952  nbBytesWritten += bw;
953  }
954  f_close(fo);
955  fileDes[lm->op.fd].inUse = false; // store that file is closed
956  }
957  }
958  }
959  break;
960 
961  case FCNTL_EXIT:
962  tlsf_free_r(&HEAP_DEFAULT, lm); // to avoid a memory leak
963  chThdExit(storageStatus = SDLOG_NOTHREAD);
964  break; /* To exit from thread when asked : chThdTerminate
965  then send special message with FCNTL_EXIT */
966 
967 
968  case FCNTL_WRITE: {
969  const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
970  if (fileDes[lm->op.fd].inUse) {
971  const int32_t messLen = retLen - (int32_t)(sizeof(LogMessage));
972  if (messLen < (SDLOG_WRITE_BUFFER_SIZE - curBufFill)) {
973  // the buffer can accept this message
974  memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(messLen));
975  perfBuffers[lm->op.fd].size = (uint16_t)((perfBuffers[lm->op.fd].size) + messLen);
976  } else {
977  // fill the buffer
978  const int32_t stayLen = SDLOG_WRITE_BUFFER_SIZE - curBufFill;
979  memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(stayLen));
980  FRESULT rc = f_write(fo, perfBuffer, SDLOG_WRITE_BUFFER_SIZE, &bw);
981  nbBytesWritten += bw;
982  // if there an autoflush period specified, flush to the mass storage media
983  // if timer has expired and rearm.
984  if (fileDes[lm->op.fd].autoFlushPeriod) {
985  const systime_t now = chVTGetSystemTimeX();
986  if ((now - fileDes[lm->op.fd].lastFlushTs) >
987  (fileDes[lm->op.fd].autoFlushPeriod * CH_CFG_ST_FREQUENCY)) {
988  f_sync(fo);
989  fileDes[lm->op.fd].lastFlushTs = now;
990  }
991  }
992  if (rc) {
993  //chThdExit(storageStatus = SDLOG_FATFS_ERROR);
994  storageStatus = SDLOG_FATFS_ERROR;
995  } else if (bw != SDLOG_WRITE_BUFFER_SIZE) {
996  chThdExit(storageStatus = SDLOG_FSFULL);
997  }
998 
999  memcpy(perfBuffer, &(lm->mess[stayLen]), (uint32_t)(messLen - stayLen));
1000  perfBuffers[lm->op.fd].size = (uint16_t)(messLen - stayLen); // curBufFill
1001  }
1002  }
1003  }
1004  }
1005  tlsf_free_r(&HEAP_DEFAULT, lm);
1006  } else {
1007  chThdExit(storageStatus = SDLOG_INTERNAL_ERROR);
1008  }
1009  }
1010 }
1011 
1012 static size_t logMessageLen(const LogMessage *lm)
1013 {
1014  return sizeof(LogMessage) + strnlen(lm->mess, SDLOG_MAX_MESSAGE_LEN);
1015 }
1016 
1017 static size_t logRawLen(const size_t len)
1018 {
1019  return sizeof(LogMessage) + len;
1020 }
1021 
1022 static SdioError getNextFIL(FileDes *fd)
1023 {
1024  // if there is a free slot in fileDes, use it
1025  // else, if all slots are buzy, maximum open files limit
1026  // is reach.
1027  for (FileDes i = 0; i < SDLOG_NUM_FILES; i++) {
1028  if (fileDes[i].inUse == false) {
1029  *fd = i;
1030  fileDes[i].inUse = true;
1031  return SDLOG_OK;
1032  }
1033  }
1034  return SDLOG_FDFULL;
1035 }
1036 
1037 size_t sdLogGetNbBytesWrittenToStorage(void)
1038 {
1039  return nbBytesWritten;
1040 }
1041 
1042 SdioError sdLogGetStorageStatus(void)
1043 {
1044  return storageStatus;
1045 }
1046 
1047 
1048 #endif
SDLOG_WRITE_BUFFER_SIZE
#define SDLOG_WRITE_BUFFER_SIZE
Definition: sdLog.c:71
uint32_t
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
uint8_t
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
SDLOG_FSFULL
@ SDLOG_FSFULL
Definition: sdLog.h:116
msgqueue_pop
int32_t msgqueue_pop(MsgQueue *que, void **msgPtr)
wait then receive message
Definition: msg_queue.c:134
NUMBERMAX
#define NUMBERMAX
Definition: sdLog.h:35
status
uint8_t status
Definition: nps_radio_control_spektrum.c:101
tlsf_stat_r
void tlsf_stat_r(tlsf_memory_heap_t *heap, struct tlsf_stat_t *stat)
Definition: tlsf_malloc_arch.c:127
SDLOG_OK
@ SDLOG_OK
Definition: sdLog.h:112
SDLOG_FATFS_ERROR
@ SDLOG_FATFS_ERROR
Definition: sdLog.h:114
IN_DMA_SECTION
static IN_DMA_SECTION(FATFS fatfs)
SdLogBuffer
struct _SdLogBuffer SdLogBuffer
Definition: sdLog.h:127
SDLOG_FDFULL
@ SDLOG_FDFULL
Definition: sdLog.h:117
sdLog.h
sdLogFinish
SdioError sdLogFinish(void)
unmount filesystem
Definition: sdLog.c:251
SDLOG_INTERNAL_ERROR
@ SDLOG_INTERNAL_ERROR
Definition: sdLog.h:121
SDLOG_MAX_MESSAGE_LEN
#define SDLOG_MAX_MESSAGE_LEN
Definition: mcuconf.h:456
SDLOG_QUEUE_BUCKETS
#define SDLOG_QUEUE_BUCKETS
Definition: mcuconf.h:455
chsnprintf
void chsnprintf(char *buffer, size_t size, const char *fmt,...)
Definition: printf.c:377
CH_CFG_ST_FREQUENCY
#define CH_CFG_ST_FREQUENCY
System tick frequency.
Definition: chconf.h:75
SDLOG_FATFS_NOENT
@ SDLOG_FATFS_NOENT
Definition: sdLog.h:115
MIN
#define MIN(x, y)
Definition: sdLog.c:39
MsgQueue::mb
mailbox_t mb
Definition: msg_queue.h:226
SDLOG_MEMFULL
@ SDLOG_MEMFULL
Definition: sdLog.h:119
DWORD
uint32_t DWORD
Definition: usb_msd.c:133
NUMBERFMF
#define NUMBERFMF
Definition: sdLog.h:36
MsgQueue_REGULAR
@ MsgQueue_REGULAR
Definition: msg_queue.h:47
SDLOG_QUEUEFULL
@ SDLOG_QUEUEFULL
Definition: sdLog.h:118
dir
static const float dir[]
Definition: shift_tracking.c:91
printf.h
Mini printf-like functionality.
SDLOG_NOTHREAD
@ SDLOG_NOTHREAD
Definition: sdLog.h:120
sdio_disconnect
bool sdio_disconnect(void)
Disconnect a SD card on SDIO peripheral.
Definition: sdio_arch.c:73
SDLOG_NUM_FILES
#define SDLOG_NUM_FILES
Definition: mcuconf.h:457
removeEmptyLogs
SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
remove spurious log file left on sd
Definition: sdLog.c:780
sdio.h
arch independent SDIO API
tlsf_realloc_r
void * tlsf_realloc_r(tlsf_memory_heap_t *heap, void *ptr, size_t bytes)
Definition: tlsf_malloc_arch.c:111
tlsf_free_r
void tlsf_free_r(tlsf_memory_heap_t *heap, void *ptr)
Definition: tlsf_malloc_arch.c:119
true
#define true
Definition: microrl.h:6
msgqueue_pop_timeout
int32_t msgqueue_pop_timeout(MsgQueue *que, void **msgPtr, const systime_t timout)
receive message specifying timeout
Definition: msg_queue.c:139
msgqueue_init
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
msgqueue_send
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
msg_queue.h
SDLOG_CANNOT_EXPAND
@ SDLOG_CANNOT_EXPAND
Definition: sdLog.h:122
FileDes
int8_t FileDes
Definition: sdLog.h:128
MsgQueue_OUT_OF_BAND
@ MsgQueue_OUT_OF_BAND
Definition: msg_queue.h:47
SDLOG_NOCARD
@ SDLOG_NOCARD
Definition: sdLog.h:113
fd
int fd
Definition: serial.c:26
int32_t
int int32_t
Typedef defining 32 bit int type.
Definition: vl53l1_types.h:83
tlsf_malloc_r
void * tlsf_malloc_r(tlsf_memory_heap_t *heap, size_t bytes)
Definition: tlsf_malloc_arch.c:95
offset
static const float offset[]
Definition: dw1000_arduino.c:199
msgqueue_copy_send
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
chvsnprintf
void chvsnprintf(char *buffer, size_t size, const char *fmt, va_list ap)
Definition: printf.c:372
ram_arch.h
MAX
#define MAX(x, y)
Definition: sdLog.c:42
sdio_connect
bool sdio_connect(void)
Connect a SD card on SDIO peripheral.
Definition: sdio_arch.c:48
flushWriteByteBuffer
static SdioError flushWriteByteBuffer(const FileDes fd)
getFileName
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:719
tlsf_stat_t
Definition: tlsf_malloc.h:55
IN_STD_SECTION_CLEAR
#define IN_STD_SECTION_CLEAR(var)
Definition: ram_arch.h:76
SDLOG_WAS_LAUNCHED
@ SDLOG_WAS_LAUNCHED
Definition: sdLog.h:124
FALSE
#define FALSE
Definition: std.h:5
FF_MAX_LFN
#define FF_MAX_LFN
Definition: ffconf.h:121
SdioError
SdioError
Definition: sdLog.h:111
uint16_t
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
IN_DMA_SECTION_NOINIT
#define IN_DMA_SECTION_NOINIT(var)
Definition: ram_arch.h:83
fo
static int fo
Definition: chdk_pipe.c:24
THD_WORKING_AREA
THD_WORKING_AREA(wa_thd_ap, THD_WORKING_AREA_MAIN)
MsgQueue
Definition: msg_queue.h:225
SDLOG_LOGNUM_ERROR
@ SDLOG_LOGNUM_ERROR
Definition: sdLog.h:123
uiGetIndexOfLogFile
static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
Definition: sdLog.c:840
sdLogInit
SdioError sdLogInit(uint32_t *freeSpaceInKo)
initialise sdLog
Definition: sdLog.c:191
HEAP_DEFAULT
#define HEAP_DEFAULT
Definition: tlsf_malloc_arch.h:44
IN_DMA_SECTION_CLEAR
#define IN_DMA_SECTION_CLEAR(var)
Definition: ram_arch.h:84