Paparazzi UAS  v5.10_stable-5-g83a0da5-dirty
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
39 #define likely(x) __builtin_expect(!!(x), 1)
40 #define unlikely(x) __builtin_expect(!!(x), 0)
41 
42 #define MIN(x , y) (((x) < (y)) ? (x) : (y))
43 #define MAX(x , y) (((x) > (y)) ? (x) : (y))
44 
45 
46 // Number of files opened simultaneously
47 // Set to 2 by default since we have the default log file
48 // and optionally the flight recorder file
49 //
50 // WARNING:
51 // - if _FS_LOCK is set to 0, there is no limit on simultaneously opened file,
52 // but no file locking, all fatfs operations should be done from same thread
53 // - if _FS_LOCK is > 0, each file is in a different subdir, so _FS_LOCK should
54 // be set to 2 * nbFile
55 #ifndef SDLOG_NUM_BUFFER
56 #define SDLOG_NUM_BUFFER 2
57 #endif
58 
59 #ifndef SDLOG_ALL_BUFFERS_SIZE
60 #error SDLOG_ALL_BUFFERS_SIZE should be defined in mcuconf.h
61 #endif
62 
63 #define SDLOG_WRITE_BUFFER_SIZE (SDLOG_ALL_BUFFERS_SIZE/SDLOG_NUM_BUFFER)
64 
65 #ifndef SDLOG_MAX_MESSAGE_LEN
66 #error SDLOG_MAX_MESSAGE_LEN should be defined in mcuconf.h
67 #endif
68 
69 #ifndef SDLOG_QUEUE_BUCKETS
70 #error SDLOG_QUEUE_BUCKETS should be defined in mcuconf.h
71 #endif
72 
73 #if _FS_REENTRANT == 0
74 #warning "_FS_REENTRANT = 0 in ffconf.h DO NOT open close file during log"
75 #endif
76 
77 
78 #ifdef SDLOG_NEED_QUEUE
80 
81 #if defined STM32F4XX
82 #define NODMA_SECTION ".ram4"
83 #define DMA_SECTION ".ram0"
84 #elif defined STM32F7XX
85 #define NODMA_SECTION ".ram0"
86 #define DMA_SECTION ".ram3"
87 #else
88 #error "section defined only for STM32F4 and STM32F7"
89 #endif
90 
91 static msg_t queMbBuffer[SDLOG_QUEUE_BUCKETS] __attribute__((section(NODMA_SECTION), aligned(8))) ;
92 static MsgQueue messagesQueue;
93 
94 #define WRITE_BYTE_CACHE_SIZE 15 // limit overhead :
95 // malloc (15+1) occupies 20bytes
96 typedef struct {
97  uint8_t fcntl: 2;
98  uint8_t fd: 6;
99 } FileOp;
100 
101 struct LogMessage {
102  FileOp op;
103  char mess[0];
104 };
105 
106 struct FilePoolUnit {
107  FIL fil;
108  bool inUse;
109  bool tagAtClose;
110  // optimise write byte by caching at send level now that we are based upon tlsf where
111  // allocation granularity is 16 bytes
112  LogMessage *writeByteCache;
113  uint8_t writeByteSeek;
114 };
115 
116 static struct FilePoolUnit fileDes[SDLOG_NUM_BUFFER] = {
117  [0 ... SDLOG_NUM_BUFFER - 1] = {
118  .fil = {0}, .inUse = false, .tagAtClose = false,
119  .writeByteCache = NULL, .writeByteSeek = 0
120  }
121 };
122 
123 typedef enum {
124  FCNTL_WRITE = 0b00,
125  FCNTL_FLUSH = 0b01,
126  FCNTL_CLOSE = 0b10,
127  FCNTL_EXIT = 0b11
128 } FileFcntl;
129 
130 struct _SdLogBuffer {
131  LogMessage *lm;
132  size_t len;
134 };
135 
136 
137 
138 #define LOG_MESSAGE_PREBUF_LEN (SDLOG_MAX_MESSAGE_LEN+sizeof(LogMessage))
139 #endif // SDLOG_NEED_QUEUE
140 
141 
142 static FATFS fatfs; /* File system object */
143 
144 #ifdef SDLOG_NEED_QUEUE
145 static size_t logMessageLen(const LogMessage *lm);
146 static size_t logRawLen(const size_t len);
147 static SdioError sdLoglaunchThread(void);
148 static SdioError sdLogStopThread(void);
149 static thread_t *sdLogThd = NULL;
150 static SdioError getNextFIL(FileDes *fd);
151 
152 #if (CH_KERNEL_MAJOR > 2)
153 static void thdSdLog(void *arg) ;
154 #else
155 static msg_t thdSdLog(void *arg) ;
156 #endif
157 
158 #endif // SDLOG_NEED_QUEUE
159 
160 
161 
162 
163 static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName) ;
164 static inline SdioError flushWriteByteBuffer(const FileDes fd);
165 
166 SdioError sdLogInit(uint32_t *freeSpaceInKo)
167 {
168  DWORD clusters = 0;
169  FATFS *fsp = NULL;
170 
171  // if init is already done, return ERROR
172  if (sdLogThd != NULL) {
173  *freeSpaceInKo = 0;
174  return SDLOG_WAS_LAUNCHED;
175  }
176 
177 #ifdef SDLOG_NEED_QUEUE
178  msgqueue_init(&messagesQueue, &HEAP_DEFAULT, queMbBuffer, SDLOG_QUEUE_BUCKETS);
179 #endif
180 
181  if (!sdc_lld_is_card_inserted(NULL)) {
182  return SDLOG_NOCARD;
183  }
184 
185 
186  sdio_connect();
187  chThdSleepMilliseconds(10);
188  sdio_disconnect();
189 
190  if (sdio_connect() == false) {
191  return SDLOG_NOCARD;
192  }
193 
194 #if _FATFS < 8000
195  FRESULT rc = f_mount(0, &fatfs);
196 #else
197  FRESULT rc = f_mount(&fatfs, "/", 1);
198 #endif
199 
200  if (rc != FR_OK) {
201  return SDLOG_FATFS_ERROR;
202  }
203 
204  if (freeSpaceInKo != NULL) {
205  f_getfree("/", &clusters, &fsp);
206  *freeSpaceInKo = clusters * (uint32_t)fatfs.csize / 2;
207  }
208 
209 #ifdef SDLOG_NEED_QUEUE
210  for (uint8_t i = 0; i < SDLOG_NUM_BUFFER; i++) {
211  fileDes[i].inUse = fileDes[i].tagAtClose = false;
212  fileDes[i].writeByteCache = NULL;
213  fileDes[i].writeByteSeek = 0;
214  }
215 
216  return sdLoglaunchThread();
217 #else
218  return SDLOG_OK;
219 #endif
220 
221 }
222 
223 
225 {
226 #if _FATFS < 8000
227  FRESULT rc = f_mount(0, NULL);
228 #else
229  FRESULT rc = f_mount(NULL, "", 0);
230 #endif
231  if (rc != FR_OK) {
232  return SDLOG_FATFS_ERROR;
233  }
234 
235  // if we mount, unmount, don't disconnect sdio
236  /* if (sdio_disconnect () == false) */
237  /* return SDLOG_NOCARD; */
238 
239  return SDLOG_OK ;
240 }
241 
242 
243 
244 #ifdef SDLOG_NEED_QUEUE
245 SdioError sdLogOpenLog(FileDes *fd, const char *directoryName, const char *prefix,
246  bool appendTagAtClose)
247 {
248  FRESULT rc; /* fatfs result code */
249  SdioError sde; /* sdio result code */
250  //DIR dir; /* Directory object */
251  //FILINFO fno; /* File information object */
252  char fileName[32];
253 
254  sde = getNextFIL(fd);
255  if (sde != SDLOG_OK) {
256  return sde;
257  }
258 
259  sde = getFileName(prefix, directoryName, fileName, sizeof(fileName), +1);
260  if (sde != SDLOG_OK) {
261  // sd card is not inserted, so logging task can be deleted
262  return SDLOG_FATFS_ERROR;
263  }
264 
265 
266  rc = f_open(&fileDes[*fd].fil, fileName, FA_WRITE | FA_CREATE_ALWAYS);
267  if (rc) {
268  fileDes[*fd].inUse = false;
269  return SDLOG_FATFS_ERROR;
270  } else {
271  fileDes[*fd].tagAtClose = appendTagAtClose;
272  }
273 
274  return SDLOG_OK;
275 }
276 
277 
278 SdioError sdLogCloseAllLogs(bool flush)
279 {
280  FRESULT rc = 0; /* Result code */
281 
282 
283 
284  // do not flush what is in ram, close as soon as possible
285  if (flush == false) {
286  // stop worker thread then close file
287  sdLogStopThread();
288  for (FileDes fd = 0; fd < SDLOG_NUM_BUFFER; fd++) {
289  if (fileDes[fd].inUse) {
290  FIL *fileObject = &fileDes[fd].fil;
291 
292  FRESULT trc = f_close(fileObject);
293  fileDes[fd].inUse = false;
294  if (!rc) {
295  rc = trc;
296  }
297  }
298  }
299 
300  if (rc) {
301  return SDLOG_FATFS_ERROR;
302  }
303 
304  // flush ram buffer then close
305  } else { // flush == true
306  if (sdLogThd == NULL) {
307  // something goes wrong, log thread is no more working
308  return SDLOG_NOTHREAD;
309  }
310 
311  // queue flush + close order, then stop worker thread
312  for (FileDes fd = 0; fd < SDLOG_NUM_BUFFER; fd++) {
313  if (fileDes[fd].inUse) {
315  sdLogCloseLog(fd);
316  }
317  }
318 
319  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
320  if (lm == NULL) {
321  return SDLOG_QUEUEFULL;
322  }
323 
324  lm->op.fcntl = FCNTL_EXIT;
325 
326  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
327  return SDLOG_QUEUEFULL;
328  } else {
329  chThdWait(sdLogThd);
330  sdLogThd = NULL;
331  }
332 
333  }
334  return SDLOG_OK;
335 }
336 
337 
338 
339 SdioError sdLogWriteLog(const FileDes fd, const char *fmt, ...)
340 {
341  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
342  return SDLOG_FATFS_ERROR;
343  }
344 
346  if (status != SDLOG_OK) {
347  return status;
348  }
349 
350  va_list ap;
351  va_start(ap, fmt);
352 
353  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, LOG_MESSAGE_PREBUF_LEN);
354  if (lm == NULL) {
355  va_end(ap);
356  return SDLOG_QUEUEFULL;
357  }
358 
359  lm->op.fcntl = FCNTL_WRITE;
360  lm->op.fd = fd & 0x1f;
361 
362  chvsnprintf(lm->mess, SDLOG_MAX_MESSAGE_LEN - 1, fmt, ap);
363  lm->mess[SDLOG_MAX_MESSAGE_LEN - 1] = 0;
364  va_end(ap);
365 
366  const size_t msgLen = logMessageLen(lm);
367  lm = tlsf_realloc_r(&HEAP_DEFAULT, lm, msgLen);
368  if (lm == NULL) {
369  return SDLOG_QUEUEFULL;
370  }
371 
372  if (msgqueue_send(&messagesQueue, lm, msgLen, MsgQueue_REGULAR) < 0) {
373  return SDLOG_QUEUEFULL;
374  }
375 
376  return SDLOG_OK;
377 }
378 
379 SdioError sdLogFlushLog(const FileDes fd)
380 {
381  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
382  return SDLOG_FATFS_ERROR;
383  }
384 
385  const SdioError status = flushWriteByteBuffer(fd);
386  if (status != SDLOG_OK) {
387  return status;
388  }
389 
390  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
391  if (lm == NULL) {
392  return SDLOG_QUEUEFULL;
393  }
394 
395  lm->op.fcntl = FCNTL_FLUSH;
396  lm->op.fd = fd & 0x1f;
397 
398  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
399  return SDLOG_QUEUEFULL;
400  }
401 
402  return SDLOG_OK;
403 }
404 
405 SdioError sdLogCloseLog(const FileDes fd)
406 {
407  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
408  return SDLOG_FATFS_ERROR;
409  }
410 
411  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage));
412  if (lm == NULL) {
413  return SDLOG_QUEUEFULL;
414  }
415 
416  lm->op.fcntl = FCNTL_CLOSE;
417  lm->op.fd = fd & 0x1f;
418 
419  if (msgqueue_send(&messagesQueue, lm, sizeof(LogMessage), MsgQueue_REGULAR) < 0) {
420  return SDLOG_QUEUEFULL;
421  }
422 
423  return SDLOG_OK;
424 }
425 
426 
427 
428 
429 
430 static inline SdioError flushWriteByteBuffer(const FileDes fd)
431 {
432  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
433  return SDLOG_FATFS_ERROR;
434  }
435 
436  if (unlikely(fileDes[fd].writeByteCache != NULL)) {
437  if (msgqueue_send(&messagesQueue, fileDes[fd].writeByteCache,
438  sizeof(LogMessage) + fileDes[fd].writeByteSeek,
439  MsgQueue_REGULAR) < 0) {
440  return SDLOG_QUEUEFULL;
441  }
442  fileDes[fd].writeByteCache = NULL;
443  }
444  return SDLOG_OK;
445 }
446 
447 SdioError sdLogWriteRaw(const FileDes fd, const uint8_t *buffer, const size_t len)
448 {
449  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
450  return SDLOG_FATFS_ERROR;
451  }
452 
453  const SdioError status = flushWriteByteBuffer(fd);
454  if (status != SDLOG_OK) {
455  return status;
456  }
457 
458  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
459  if (lm == NULL) {
460  return SDLOG_QUEUEFULL;
461  }
462 
463  lm->op.fcntl = FCNTL_WRITE;
464  lm->op.fd = fd & 0x1f;
465  memcpy(lm->mess, buffer, len);
466 
467  if (msgqueue_send(&messagesQueue, lm, logRawLen(len), MsgQueue_REGULAR) < 0) {
468  return SDLOG_QUEUEFULL;
469  }
470 
471  return SDLOG_OK;
472 }
473 
474 SdioError sdLogAllocSDB(SdLogBuffer **sdb, const size_t len)
475 {
476  *sdb = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
477  if (*sdb == NULL) {
478  return SDLOG_QUEUEFULL;
479  }
480 
481  LogMessage *lm = tlsf_malloc_r(&HEAP_DEFAULT, logRawLen(len));
482  if (lm == NULL) {
483  tlsf_free_r(&HEAP_DEFAULT, *sdb);
484  return SDLOG_QUEUEFULL;
485  }
486 
487  (*sdb)->lm = lm;
488  (*sdb)->len = len;
489  (*sdb)->offset = 0;
490  return SDLOG_OK;
491 }
492 
493 char *sdLogGetBufferFromSDB(SdLogBuffer *sdb)
494 {
495  return sdb->lm->mess + sdb->offset;
496 }
497 
498 bool sdLogSeekBufferFromSDB(SdLogBuffer *sdb, uint32_t offset)
499 {
500  if ((sdb->offset + offset) < sdb->len) {
501  sdb->offset += offset;
502  return true;
503  } else {
504  return false;
505  }
506 }
507 
508 size_t sdLogGetBufferLenFromSDB(SdLogBuffer *sdb)
509 {
510  return sdb->len - sdb->offset;
511 }
512 
513 SdioError sdLogWriteSDB(const FileDes fd, SdLogBuffer *sdb)
514 {
515  SdioError status = SDLOG_OK;
516 
517  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
518  status = SDLOG_FATFS_ERROR;
519  goto fail;
520  }
521 
522  status = flushWriteByteBuffer(fd);
523  if (status != SDLOG_OK) {
524  goto fail;
525  }
526 
527  sdb->lm->op.fcntl = FCNTL_WRITE;
528  sdb->lm->op.fd = fd & 0x1f;
529 
530  if (msgqueue_send(&messagesQueue, sdb->lm, logRawLen(sdb->len), MsgQueue_REGULAR) < 0) {
531  // msgqueue_send take care of freeing lm memory even in case of failure
532  // just need to free sdb memory
533  status = SDLOG_QUEUEFULL;
534  }
535 
536  goto exit;
537 
538 fail:
539  tlsf_free_r(&HEAP_DEFAULT, sdb->lm);
540 
541 exit:
542  tlsf_free_r(&HEAP_DEFAULT, sdb);
543  return status;
544 }
545 
546 
547 
548 SdioError sdLogWriteByte(const FileDes fd, const uint8_t value)
549 {
550  if ((fd >= SDLOG_NUM_BUFFER) || (fileDes[fd].inUse == false)) {
551  return SDLOG_FATFS_ERROR;
552  }
553  LogMessage *lm;
554 
555  if (fileDes[fd].writeByteCache == NULL) {
556  lm = tlsf_malloc_r(&HEAP_DEFAULT, sizeof(LogMessage) + WRITE_BYTE_CACHE_SIZE);
557  if (lm == NULL) {
558  return SDLOG_QUEUEFULL;
559  }
560 
561  lm->op.fcntl = FCNTL_WRITE;
562  lm->op.fd = fd & 0x1f;
563 
564  fileDes[fd].writeByteCache = lm;
565  fileDes[fd].writeByteSeek = 0;
566  } else {
567  lm = fileDes[fd].writeByteCache;
568  }
569 
570  lm->mess[fileDes[fd].writeByteSeek++] = value;
571 
572  if (fileDes[fd].writeByteSeek == WRITE_BYTE_CACHE_SIZE) {
573  const SdioError status = flushWriteByteBuffer(fd);
574  // message is not sent so allocated buffer will not be released by receiver side
575  // instead of freeing buffer, we just reset cache seek.
576  if (status == SDLOG_QUEUEFULL) {
577  fileDes[fd].writeByteSeek = 0;
578  return status;
579  }
580  }
581 
582  return SDLOG_OK;
583 }
584 
585 
586 
587 
588 /* enregistrer les fichiers ouverts de manière à les fermer
589  si necessaire
590  */
591 static THD_WORKING_AREA(waThdSdLog, 1024);
592 SdioError sdLoglaunchThread()
593 {
594  chThdSleepMilliseconds(100);
595 
596  sdLogThd = chThdCreateStatic(waThdSdLog, sizeof(waThdSdLog),
597  NORMALPRIO + 1, thdSdLog, NULL);
598  if (sdLogThd == NULL) {
599  return SDLOG_INTERNAL_ERROR;
600  } else {
601  return SDLOG_OK;
602  }
603 }
604 
605 SdioError sdLogStopThread(void)
606 {
607  SdioError retVal = SDLOG_OK;
608 
609  if (sdLogThd == NULL) {
610  return SDLOG_NOTHREAD;
611  }
612 
613  LogMessage lm;
614 
615  // ask for closing (after flushing) all opened files
616  for (uint8_t i = 0; i < SDLOG_NUM_BUFFER; i++) {
617  if (fileDes[i].inUse) {
619  lm.op.fcntl = FCNTL_CLOSE;
620  lm.op.fd = i & 0x1f;
621  if (msgqueue_copy_send(&messagesQueue, &lm, sizeof(LogMessage), MsgQueue_OUT_OF_BAND) < 0) {
622  retVal = SDLOG_QUEUEFULL;
623  }
624  }
625  }
626 
627  lm.op.fcntl = FCNTL_EXIT;
628  if (msgqueue_copy_send(&messagesQueue, &lm, sizeof(LogMessage), MsgQueue_OUT_OF_BAND) < 0) {
629  retVal = SDLOG_QUEUEFULL;
630  }
631 
632  chThdTerminate(sdLogThd);
633  chThdWait(sdLogThd);
634  sdLogThd = NULL;
635  return retVal;
636 }
637 #endif
638 
639 
640 SdioError getFileName(const char *prefix, const char *directoryName,
641  char *nextFileName, const size_t nameLength, const int indexOffset)
642 {
643  DIR dir; /* Directory object */
644  FRESULT rc; /* Result code */
645  FILINFO fno; /* File information object */
646  int32_t fileIndex ;
647  int32_t maxCurrentIndex = 0;
648  char *fn; /* This function is assuming non-Unicode cfg. */
649 #if _USE_LFN
650  char lfn[_MAX_LFN + 1];
651  fno.lfname = lfn;
652  fno.lfsize = sizeof lfn;
653 #endif
654  const size_t directoryNameLen = MIN(strlen(directoryName), 128);
655  const size_t slashDirNameLen = directoryNameLen + 2;
656  char slashDirName[slashDirNameLen];
657  strlcpy(slashDirName, "/", slashDirNameLen);
658  strlcat(slashDirName, directoryName, slashDirNameLen);
659 
660  rc = f_opendir(&dir, directoryName);
661  if (rc != FR_OK) {
662  rc = f_mkdir(slashDirName);
663  if (rc != FR_OK) {
664  return SDLOG_FATFS_ERROR;
665  }
666  rc = f_opendir(&dir, directoryName);
667  if (rc != FR_OK) {
668  return SDLOG_FATFS_ERROR;
669  }
670  }
671 
672  for (;;) {
673  rc = f_readdir(&dir, &fno); /* Read a directory item */
674  if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
675 #if _USE_LFN
676  fn = *fno.lfname ? fno.lfname : fno.fname;
677 #else
678  fn = fno.fname;
679 #endif
680  if (fn[0] == '.') { continue; }
681 
682  if (!(fno.fattrib & AM_DIR)) {
683  // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
684  fileIndex = uiGetIndexOfLogFile(prefix, fn);
685  maxCurrentIndex = MAX(maxCurrentIndex, fileIndex);
686  }
687  }
688  if (rc) {
689  return SDLOG_FATFS_ERROR;
690  }
691 
692  rc = f_closedir(&dir);
693  if (rc) {
694  return SDLOG_FATFS_ERROR;
695  }
696 
697  if (maxCurrentIndex < NUMBERMAX) {
698  chsnprintf(nextFileName, nameLength, NUMBERFMF,
699  directoryName, prefix, maxCurrentIndex + indexOffset);
700  return SDLOG_OK;
701  } else {
702  chsnprintf(nextFileName, nameLength, "%s\\%s%.ERR",
703  directoryName, prefix);
704  return SDLOG_LOGNUM_ERROR;
705  }
706 }
707 
708 SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
709 {
710  DIR dir; /* Directory object */
711  FRESULT rc; /* Result code */
712  FILINFO fno; /* File information object */
713  char *fn; /* This function is assuming non-Unicode cfg. */
714 #if _USE_LFN
715  char lfn[_MAX_LFN + 1];
716  fno.lfname = lfn;
717  fno.lfsize = sizeof lfn;
718 #endif
719 
720  rc = f_opendir(&dir, directoryName);
721  if (rc != FR_OK) {
722  return SDLOG_FATFS_NOENT;
723  }
724 
725  for (;;) {
726  rc = f_readdir(&dir, &fno); /* Read a directory item */
727  if (rc != FR_OK || fno.fname[0] == 0) { break; } /* Error or end of dir */
728 #if _USE_LFN
729  fn = *fno.lfname ? fno.lfname : fno.fname;
730 #else
731  fn = fno.fname;
732 #endif
733  if (fn[0] == '.') { continue; }
734 
735  if (!(fno.fattrib & AM_DIR)) {
736  // DebugTrace ("fno.fsize=%d fn=%s\n", fno.fsize, fn);
737  if ((strncmp(fn, prefix, strlen(prefix)) == 0) && (fno.fsize <= sizeConsideredEmpty)) {
738  char absPathName[128];
739  strlcpy(absPathName, directoryName, sizeof(absPathName));
740  strlcat(absPathName, "/", sizeof(absPathName));
741  strlcat(absPathName, fn, sizeof(absPathName));
742  rc = f_unlink(absPathName);
743  if (rc) {
744  break;
745  }
746  }
747  }
748  }
749 
750  if (rc) {
751  return SDLOG_FATFS_ERROR;
752  }
753 
754  rc = f_closedir(&dir);
755  if (rc) {
756  return SDLOG_FATFS_ERROR;
757  }
758 
759  return SDLOG_OK;
760 }
761 
762 /*
763 # _____ _ _
764 # | __ \ (_) | |
765 # | |__) | _ __ _ __ __ __ _ | |_ ___
766 # | ___/ | '__| | | \ \ / / / _` | | __| / _ \
767 # | | | | | | \ V / | (_| | \ |_ | __/
768 # |_| |_| |_| \_/ \__,_| \__| \___|
769 */
770 
771 
772 
773 
774 
775 
776 
777 int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
778 {
779  const size_t len = strlen(prefix);
780 
781  // if filename does not began with prefix, return 0
782  if (strncmp(prefix, fileName, len) != 0) {
783  return 0;
784  }
785 
786  // we point on the first char after prefix
787  const char *suffix = &(fileName[len]);
788 
789  // we test that suffix is valid (at least begin with digit)
790  if (!isdigit((int) suffix[0])) {
791  // DebugTrace ("DBG> suffix = %s", suffix);
792  return 0;
793  }
794 
795  return (int32_t) atoi(suffix);
796 }
797 
798 
799 #ifdef SDLOG_NEED_QUEUE
800 #if (CH_KERNEL_MAJOR > 2)
801 static void thdSdLog(void *arg)
802 #else
803 static msg_t thdSdLog(void *arg)
804 #endif
805 {
806  (void) arg;
807  struct PerfBuffer {
809  uint16_t size;
810  } ;
811 
812  UINT bw;
813  static struct PerfBuffer perfBuffers[SDLOG_NUM_BUFFER] __attribute__((section(DMA_SECTION), aligned(8))) = {
814  [0 ... SDLOG_NUM_BUFFER - 1] = {.buffer = {0}, .size = 0}
815  };
816 
817  // FIXME above initialization doesn't seem to work for all GCC version
818  // for now, also doing the good old way.
819  memset(perfBuffers, 0, SDLOG_NUM_BUFFER * sizeof(struct PerfBuffer));
820 
821  chRegSetThreadName("thdSdLog");
822  while (!chThdShouldTerminateX()) {
823  LogMessage *lm;
824  const int32_t retLen = (int32_t)(msgqueue_pop(&messagesQueue, (void **) &lm));
825  if (retLen > 0) {
826  FIL *fo = &fileDes[lm->op.fd].fil;
827  uint8_t *const perfBuffer = perfBuffers[lm->op.fd].buffer;
828 
829  switch (lm->op.fcntl) {
830 
831  case FCNTL_FLUSH:
832  case FCNTL_CLOSE: {
833  const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
834  if (fileDes[lm->op.fd].inUse) {
835  if (curBufFill) {
836  f_write(fo, perfBuffer, curBufFill, &bw);
837  perfBuffers[lm->op.fd].size = 0;
838  }
839  if (lm->op.fcntl == FCNTL_FLUSH) {
840  f_sync(fo);
841  } else { // close
842  if (fileDes[lm->op.fd].tagAtClose) {
843  f_write(fo, "\r\nEND_OF_LOG\r\n", 14, &bw);
844  }
845  f_close(fo);
846  fileDes[lm->op.fd].inUse = false; // store that file is closed
847  }
848  }
849  }
850  break;
851 
852  case FCNTL_EXIT:
853  chThdExit(SDLOG_OK);
854  break; /* To exit from thread when asked : chThdTerminate
855  then send special message with FCNTL_EXIT */
856 
857 
858  case FCNTL_WRITE: {
859  const uint16_t curBufFill = perfBuffers[lm->op.fd].size;
860  if (fileDes[lm->op.fd].inUse) {
861  const int32_t messLen = retLen - (int32_t)(sizeof(LogMessage));
862  if (messLen < (SDLOG_WRITE_BUFFER_SIZE - curBufFill)) {
863  // the buffer can accept this message
864  memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(messLen));
865  perfBuffers[lm->op.fd].size = (uint16_t)((perfBuffers[lm->op.fd].size) + messLen);
866  } else {
867  // fill the buffer
868  const int32_t stayLen = SDLOG_WRITE_BUFFER_SIZE - curBufFill;
869  memcpy(&(perfBuffer[curBufFill]), lm->mess, (size_t)(stayLen));
870  FRESULT rc = f_write(fo, perfBuffer, SDLOG_WRITE_BUFFER_SIZE, &bw);
871  f_sync(fo);
872  if (rc) {
873  chThdExit(SDLOG_FATFS_ERROR);
874  } else if (bw != SDLOG_WRITE_BUFFER_SIZE) {
875  chThdExit(SDLOG_FSFULL);
876  }
877 
878  memcpy(perfBuffer, &(lm->mess[stayLen]), (uint32_t)(messLen - stayLen));
879  perfBuffers[lm->op.fd].size = (uint16_t)(messLen - stayLen); // curBufFill
880  }
881  }
882  }
883  }
885  } else {
886  chThdExit(SDLOG_INTERNAL_ERROR);
887  }
888  }
889 #if (CH_KERNEL_MAJOR == 2)
890  return SDLOG_OK;
891 #endif
892 }
893 
894 static size_t logMessageLen(const LogMessage *lm)
895 {
896  return sizeof(LogMessage) + strnlen(lm->mess, SDLOG_MAX_MESSAGE_LEN);
897 }
898 
899 static size_t logRawLen(const size_t len)
900 {
901  return sizeof(LogMessage) + len;
902 }
903 
904 static SdioError getNextFIL(FileDes *fd)
905 {
906  // if there is a free slot in fileDes, use it
907  // else, if all slots are buzy, maximum open files limit
908  // is reach.
909  for (FileDes i = 0; i < SDLOG_NUM_BUFFER; i++) {
910  if (fileDes[i].inUse == false) {
911  *fd = i;
912  fileDes[i].inUse = true;
913  return SDLOG_OK;
914  }
915  }
916  return SDLOG_FDFULL;
917 }
918 
919 #endif
SdioError sdLogFinish(void)
unmount filesystem
Definition: sdLog.c:224
unsigned short uint16_t
Definition: types.h:16
status
Definition: anemotaxis.c:10
#define SDLOG_NUM_BUFFER
Definition: sdLog.c:56
static struct EcefCoor_d offset
Mini printf-like functionality.
#define MAX(x, y)
Definition: sdLog.c:43
arch independent SDIO API
int8_t FileDes
Definition: sdLog.h:100
static FATFS fatfs
Definition: sdLog.c:142
static SdioError flushWriteByteBuffer(const FileDes fd)
#define SDLOG_WRITE_BUFFER_SIZE
Definition: sdLog.c:63
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
#define SDLOG_MAX_MESSAGE_LEN
Definition: mcuconf.h:387
void chsnprintf(char *buffer, size_t size, const char *fmt,...)
Definition: printf.c:377
#define HEAP_DEFAULT
static int32_t uiGetIndexOfLogFile(const char *prefix, const char *fileName)
Definition: sdLog.c:777
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:125
#define NUMBERMAX
Definition: sdLog.h:36
bool sdio_disconnect(void)
Disconnect a SD card on SDIO peripheral.
Definition: sdio_arch.c:85
#define NUMBERFMF
Definition: sdLog.h:37
void tlsf_free_r(tlsf_memory_heap_t *heap, void *ptr)
SdioError sdLogInit(uint32_t *freeSpaceInKo)
initialise sdLog
Definition: sdLog.c:166
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:640
Definition: sdLog.h:86
uint32_t DWORD
Definition: usb_msd.c:119
#define SDLOG_QUEUE_BUCKETS
Definition: mcuconf.h:388
bool sdio_connect(void)
Connect a SD card on SDIO peripheral.
Definition: sdio_arch.c:46
void * tlsf_realloc_r(tlsf_memory_heap_t *heap, void *ptr, size_t bytes)
unsigned long uint32_t
Definition: types.h:18
SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
remove spurious log file left on sd
Definition: sdLog.c:708
SdioError
Definition: sdLog.h:85
#define _MAX_LFN
Definition: ffconf.h:96
signed long int32_t
Definition: types.h:19
static int fo
Definition: chdk_pipe.c:24
void chvsnprintf(char *buffer, size_t size, const char *fmt, va_list ap)
Definition: printf.c:372
int32_t msgqueue_pop(MsgQueue *que, void **msgPtr)
wait then receive message
Definition: msg_queue.c:132
unsigned char uint8_t
Definition: types.h:14
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
int fd
Definition: serial.c:26
#define unlikely(x)
Definition: sdLog.c:40
struct _SdLogBuffer SdLogBuffer
Definition: sdLog.h:99
void * tlsf_malloc_r(tlsf_memory_heap_t *heap, size_t bytes)
static THD_WORKING_AREA(wa_thd_spi1, 1024)
#define MIN(x, y)
Definition: sdLog.c:42