Update cloud build defines (#14080)
[betaflight.git] / src / main / blackbox / blackbox_io.c
blobb981c2840d7d0e4036906b3b4017ec93519544f4
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
27 #include "platform.h"
29 #ifdef USE_BLACKBOX
31 #include "build/debug.h"
33 // Debugging code that become useful when output bandwidth saturation is suspected.
34 // Set debug_mode = BLACKBOX_OUTPUT to see following debug values.
36 // 0: Average output bandwidth in last 100ms
37 // 1: Maximum hold of above.
38 // 2: Bytes dropped due to output buffer full.
40 // Note that bandwidth usage slightly increases when DEBUG_BB_OUTPUT is enabled,
41 // as output will include debug variables themselves.
43 #define DEBUG_BB_OUTPUT
45 #include "blackbox.h"
46 #include "blackbox_io.h"
48 #include "common/maths.h"
50 #include "flight/pid.h"
52 #include "io/asyncfatfs/asyncfatfs.h"
53 #include "io/flashfs.h"
54 #include "io/serial.h"
56 #include "msp/msp_serial.h"
58 #ifdef USE_SDCARD
59 #include "drivers/sdcard.h"
60 #endif
62 #define BLACKBOX_SERIAL_PORT_MODE MODE_TX
64 // How many bytes can we transmit per loop iteration when writing headers?
65 static uint8_t blackboxMaxHeaderBytesPerIteration;
67 // How many bytes can we write *this* iteration without overflowing transmit buffers or overstressing the OpenLog?
68 int32_t blackboxHeaderBudget;
70 static serialPort_t *blackboxPort = NULL;
71 static portSharing_e blackboxPortSharing;
73 #ifdef USE_SDCARD
75 static struct {
76 afatfsFilePtr_t logFile;
77 afatfsFilePtr_t logDirectory;
78 afatfsFinder_t logDirectoryFinder;
79 int32_t largestLogFileNumber;
81 enum {
82 BLACKBOX_SDCARD_INITIAL,
83 BLACKBOX_SDCARD_WAITING,
84 BLACKBOX_SDCARD_ENUMERATE_FILES,
85 BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY,
86 BLACKBOX_SDCARD_READY_TO_CREATE_LOG,
87 BLACKBOX_SDCARD_READY_TO_LOG
88 } state;
89 } blackboxSDCard;
91 #define LOGFILE_PREFIX "LOG"
92 #define LOGFILE_SUFFIX "BFL"
94 #endif // USE_SDCARD
96 void blackboxOpen(void)
98 serialPort_t *sharedBlackboxAndMspPort = findSharedSerialPort(FUNCTION_BLACKBOX, FUNCTION_MSP);
99 if (sharedBlackboxAndMspPort) {
100 mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort);
104 #ifdef DEBUG_BB_OUTPUT
105 static uint32_t bbBits;
106 static timeMs_t bbLastclearMs;
107 static uint16_t bbRateMax;
108 static uint32_t bbDrops;
109 #endif
111 void blackboxWrite(uint8_t value)
113 #ifdef DEBUG_BB_OUTPUT
114 bbBits += 8;
115 #endif
117 switch (blackboxConfig()->device) {
118 #ifdef USE_FLASHFS
119 case BLACKBOX_DEVICE_FLASH:
120 flashfsWriteByte(value); // Write byte asynchronously
121 break;
122 #endif
123 #ifdef USE_SDCARD
124 case BLACKBOX_DEVICE_SDCARD:
125 afatfs_fputc(blackboxSDCard.logFile, value);
126 break;
127 #endif
128 case BLACKBOX_DEVICE_SERIAL:
129 default:
131 int txBytesFree = serialTxBytesFree(blackboxPort);
133 #ifdef DEBUG_BB_OUTPUT
134 bbBits += 2;
135 DEBUG_SET(DEBUG_BLACKBOX_OUTPUT, 3, txBytesFree);
136 #endif
138 if (txBytesFree == 0) {
139 #ifdef DEBUG_BB_OUTPUT
140 ++bbDrops;
141 DEBUG_SET(DEBUG_BLACKBOX_OUTPUT, 2, bbDrops);
142 #endif
143 return;
145 serialWrite(blackboxPort, value);
147 break;
150 #ifdef DEBUG_BB_OUTPUT
151 timeMs_t now = millis();
153 if (now > bbLastclearMs + 100) { // Debug log every 100[msec]
154 uint16_t bbRate = ((bbBits * 10 + 5) / (now - bbLastclearMs)) / 10; // In unit of [Kbps]
155 DEBUG_SET(DEBUG_BLACKBOX_OUTPUT, 0, bbRate);
156 if (bbRate > bbRateMax) {
157 bbRateMax = bbRate;
158 DEBUG_SET(DEBUG_BLACKBOX_OUTPUT, 1, bbRateMax);
160 bbLastclearMs = now;
161 bbBits = 0;
163 #endif
166 // Print the null-terminated string 's' to the blackbox device and return the number of bytes written
167 int blackboxWriteString(const char *s)
169 int length;
170 const uint8_t *pos;
172 switch (blackboxConfig()->device) {
174 #ifdef USE_FLASHFS
175 case BLACKBOX_DEVICE_FLASH:
176 length = strlen(s);
177 flashfsWrite((const uint8_t*) s, length, false); // Write asynchronously
178 break;
179 #endif // USE_FLASHFS
181 #ifdef USE_SDCARD
182 case BLACKBOX_DEVICE_SDCARD:
183 length = strlen(s);
184 afatfs_fwrite(blackboxSDCard.logFile, (const uint8_t*) s, length); // Ignore failures due to buffers filling up
185 break;
186 #endif // USE_SDCARD
188 case BLACKBOX_DEVICE_SERIAL:
189 default:
190 pos = (uint8_t*) s;
191 while (*pos) {
192 blackboxWrite(*pos);
193 pos++;
196 length = pos - (uint8_t*) s;
197 break;
200 return length;
204 * If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
206 * Intended to be called regularly for the blackbox device to perform housekeeping.
208 void blackboxDeviceFlush(void)
210 switch (blackboxConfig()->device) {
211 #ifdef USE_FLASHFS
213 * This is our only output device which requires us to call flush() in order for it to write anything. The other
214 * devices will progressively write in the background without Blackbox calling anything.
216 case BLACKBOX_DEVICE_FLASH:
217 flashfsFlushAsync(false);
218 break;
219 #endif // USE_FLASHFS
221 default:
227 * If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
229 * Returns true if all data has been written to the device.
231 bool blackboxDeviceFlushForce(void)
233 switch (blackboxConfig()->device) {
234 case BLACKBOX_DEVICE_SERIAL:
235 // Nothing to speed up flushing on serial, as serial is continuously being drained out of its buffer
236 return isSerialTransmitBufferEmpty(blackboxPort);
238 #ifdef USE_FLASHFS
239 case BLACKBOX_DEVICE_FLASH:
240 return flashfsFlushAsync(true);
241 #endif // USE_FLASHFS
243 #ifdef USE_SDCARD
244 case BLACKBOX_DEVICE_SDCARD:
245 // SD card will flush itself without us calling it, but we need to call flush manually in order to check
246 // if it's done yet or not!
247 // However the "flush" only queues one dirty sector each time and the process is asynchronous. So after
248 // the last dirty sector is queued the flush returns true even though the sector may not actually have
249 // been physically written to the SD card yet.
250 return afatfs_flush();
251 #endif // USE_SDCARD
253 default:
254 return false;
258 // Flush the blackbox device and only return true if sync is actually complete.
259 // Primarily to ensure the async operations of SD card sector writes complete thus freeing the cache entries.
260 bool blackboxDeviceFlushForceComplete(void)
262 switch (blackboxConfig()->device) {
263 #ifdef USE_SDCARD
264 case BLACKBOX_DEVICE_SDCARD:
265 if (afatfs_sectorCacheInSync()) {
266 return true;
267 } else {
268 blackboxDeviceFlushForce();
269 return false;
271 #endif // USE_SDCARD
273 default:
274 return blackboxDeviceFlushForce();
279 * Attempt to open the logging device. Returns true if successful.
281 bool blackboxDeviceOpen(void)
283 switch (blackboxConfig()->device) {
284 case BLACKBOX_DEVICE_SERIAL:
286 const serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_BLACKBOX);
287 baudRate_e baudRateIndex;
288 portOptions_e portOptions = SERIAL_PARITY_NO | SERIAL_NOT_INVERTED;
290 if (!portConfig) {
291 return false;
294 blackboxPortSharing = determinePortSharing(portConfig, FUNCTION_BLACKBOX);
295 baudRateIndex = portConfig->blackbox_baudrateIndex;
297 if (baudRates[baudRateIndex] == 230400) {
299 * OpenLog's 230400 baud rate is very inaccurate, so it requires a larger inter-character gap in
300 * order to maintain synchronization.
302 portOptions |= SERIAL_STOPBITS_2;
303 } else {
304 portOptions |= SERIAL_STOPBITS_1;
307 blackboxPort = openSerialPort(portConfig->identifier, FUNCTION_BLACKBOX, NULL, NULL, baudRates[baudRateIndex],
308 BLACKBOX_SERIAL_PORT_MODE, portOptions);
311 * The slowest MicroSD cards have a write latency approaching 400ms. The OpenLog's buffer is about 900
312 * bytes. In order for its buffer to be able to absorb this latency we must write slower than 6000 B/s.
314 * The OpenLager has a 125KB buffer for when the the MicroSD card is busy, so when the user configures
315 * high baud rates, assume the OpenLager is in use and so there is no need to constrain the writes.
317 * In all other cases, constrain the writes as follows:
319 * Bytes per loop iteration = floor((looptime_ns / 1000000.0) * 6000)
320 * = floor((looptime_ns * 6000) / 1000000.0)
321 * = floor((looptime_ns * 3) / 500.0)
322 * = (looptime_ns * 3) / 500
325 switch (baudRateIndex) {
326 case BAUD_1000000:
327 case BAUD_1500000:
328 case BAUD_2000000:
329 case BAUD_2470000:
330 // assume OpenLager in use, so do not constrain writes
331 blackboxMaxHeaderBytesPerIteration = BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION;
332 break;
333 default:
334 blackboxMaxHeaderBytesPerIteration = constrain((targetPidLooptime * 3) / 500, 1, BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION);
335 break;
338 return blackboxPort != NULL;
340 break;
341 #ifdef USE_FLASHFS
342 case BLACKBOX_DEVICE_FLASH:
343 if (!flashfsIsSupported() || isBlackboxDeviceFull()) {
344 return false;
347 blackboxMaxHeaderBytesPerIteration = BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION;
349 return true;
350 break;
351 #endif // USE_FLASHFS
352 #ifdef USE_SDCARD
353 case BLACKBOX_DEVICE_SDCARD:
354 if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL || afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_UNKNOWN || afatfs_isFull()) {
355 return false;
358 blackboxMaxHeaderBytesPerIteration = BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION;
360 return true;
361 break;
362 #endif // USE_SDCARD
363 default:
364 return false;
369 * Erase all blackbox logs
371 #ifdef USE_FLASHFS
372 void blackboxEraseAll(void)
374 switch (blackboxConfig()->device) {
375 case BLACKBOX_DEVICE_FLASH:
376 /* Stop the recorder as if blackbox_mode = ALWAYS it will attempt to resume writing after
377 * the erase and leave a corrupted first log.
378 * Possible enhancement here is to restart logging after erase.
380 blackboxInit();
381 flashfsEraseCompletely();
382 break;
383 default:
384 //not supported
385 break;
390 * Check to see if erasing is done
392 bool isBlackboxErased(void)
394 switch (blackboxConfig()->device) {
395 case BLACKBOX_DEVICE_FLASH:
396 return flashfsIsReady();
397 break;
398 default:
399 //not supported
400 return true;
401 break;
404 #endif
407 * Close the Blackbox logging device.
409 void blackboxDeviceClose(void)
411 switch (blackboxConfig()->device) {
412 case BLACKBOX_DEVICE_SERIAL:
413 // Can immediately close without attempting to flush any remaining data.
414 // Since the serial port could be shared with other processes, we have to give it back here
415 closeSerialPort(blackboxPort);
416 blackboxPort = NULL;
419 * Normally this would be handled by mw.c, but since we take an unknown amount
420 * of time to shut down asynchronously, we're the only ones that know when to call it.
422 if (blackboxPortSharing == PORTSHARING_SHARED) {
423 mspSerialAllocatePorts();
425 break;
426 #ifdef USE_FLASHFS
427 case BLACKBOX_DEVICE_FLASH:
428 // Some flash device, e.g., NAND devices, require explicit close to flush internally buffered data.
429 flashfsClose();
430 break;
431 #endif
432 default:
437 #ifdef USE_SDCARD
439 static void blackboxLogDirCreated(afatfsFilePtr_t directory)
441 if (directory) {
442 blackboxSDCard.logDirectory = directory;
444 afatfs_findFirst(blackboxSDCard.logDirectory, &blackboxSDCard.logDirectoryFinder);
446 blackboxSDCard.state = BLACKBOX_SDCARD_ENUMERATE_FILES;
447 } else {
448 // Retry
449 blackboxSDCard.state = BLACKBOX_SDCARD_INITIAL;
453 static void blackboxLogFileCreated(afatfsFilePtr_t file)
455 if (file) {
456 blackboxSDCard.logFile = file;
458 blackboxSDCard.largestLogFileNumber++;
460 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_LOG;
461 } else {
462 // Retry
463 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
467 static void blackboxCreateLogFile(void)
469 int32_t remainder = blackboxSDCard.largestLogFileNumber + 1;
471 char filename[] = LOGFILE_PREFIX "00000." LOGFILE_SUFFIX;
473 for (int i = 7; i >= 3; i--) {
474 filename[i] = (remainder % 10) + '0';
475 remainder /= 10;
478 blackboxSDCard.state = BLACKBOX_SDCARD_WAITING;
480 afatfs_fopen(filename, "as", blackboxLogFileCreated);
484 * Begin a new log on the SDCard.
486 * Keep calling until the function returns true (open is complete).
488 static bool blackboxSDCardBeginLog(void)
490 fatDirectoryEntry_t *directoryEntry;
492 doMore:
493 switch (blackboxSDCard.state) {
494 case BLACKBOX_SDCARD_INITIAL:
495 if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_READY) {
496 blackboxSDCard.state = BLACKBOX_SDCARD_WAITING;
498 afatfs_mkdir("logs", blackboxLogDirCreated);
500 break;
502 case BLACKBOX_SDCARD_WAITING:
503 // Waiting for directory entry to be created
504 break;
506 case BLACKBOX_SDCARD_ENUMERATE_FILES:
507 while (afatfs_findNext(blackboxSDCard.logDirectory, &blackboxSDCard.logDirectoryFinder, &directoryEntry) == AFATFS_OPERATION_SUCCESS) {
508 if (directoryEntry && !fat_isDirectoryEntryTerminator(directoryEntry)) {
509 // If this is a log file, parse the log number from the filename
510 if (strncmp(directoryEntry->filename, LOGFILE_PREFIX, strlen(LOGFILE_PREFIX)) == 0
511 && strncmp(directoryEntry->filename + 8, LOGFILE_SUFFIX, strlen(LOGFILE_SUFFIX)) == 0) {
512 char logSequenceNumberString[6];
514 memcpy(logSequenceNumberString, directoryEntry->filename + 3, 5);
515 logSequenceNumberString[5] = '\0';
517 blackboxSDCard.largestLogFileNumber = MAX((int32_t)atoi(logSequenceNumberString), blackboxSDCard.largestLogFileNumber);
519 } else {
520 // We're done checking all the files on the card, now we can create a new log file
521 afatfs_findLast(blackboxSDCard.logDirectory);
523 blackboxSDCard.state = BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY;
524 goto doMore;
527 break;
529 case BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY:
530 // Change into the log directory:
531 if (afatfs_chdir(blackboxSDCard.logDirectory)) {
532 // We no longer need our open handle on the log directory
533 afatfs_fclose(blackboxSDCard.logDirectory, NULL);
534 blackboxSDCard.logDirectory = NULL;
536 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
537 goto doMore;
539 break;
541 case BLACKBOX_SDCARD_READY_TO_CREATE_LOG:
542 blackboxCreateLogFile();
543 break;
545 case BLACKBOX_SDCARD_READY_TO_LOG:
546 return true; // Log has been created!
549 // Not finished init yet
550 return false;
553 #endif // USE_SDCARD
556 * Begin a new log (for devices which support separations between the logs of multiple flights).
558 * Keep calling until the function returns true (open is complete).
560 bool blackboxDeviceBeginLog(void)
562 switch (blackboxConfig()->device) {
563 #ifdef USE_SDCARD
564 case BLACKBOX_DEVICE_SDCARD:
565 return blackboxSDCardBeginLog();
566 #endif // USE_SDCARD
567 default:
568 return true;
574 * Terminate the current log (for devices which support separations between the logs of multiple flights).
576 * retainLog - Pass true if the log should be kept, or false if the log should be discarded (if supported).
578 * Keep calling until this returns true
580 bool blackboxDeviceEndLog(bool retainLog)
582 #ifndef USE_SDCARD
583 UNUSED(retainLog);
584 #endif
586 switch (blackboxConfig()->device) {
587 #ifdef USE_SDCARD
588 case BLACKBOX_DEVICE_SDCARD:
589 // Keep retrying until the close operation queues
590 if (
591 (retainLog && afatfs_fclose(blackboxSDCard.logFile, NULL))
592 || (!retainLog && afatfs_funlink(blackboxSDCard.logFile, NULL))
594 // Don't bother waiting the for the close to complete, it's queued now and will complete eventually
595 blackboxSDCard.logFile = NULL;
596 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
597 return true;
599 return false;
600 #endif // USE_SDCARD
601 default:
602 return true;
606 bool isBlackboxDeviceFull(void)
608 switch (blackboxConfig()->device) {
609 case BLACKBOX_DEVICE_SERIAL:
610 return false;
612 #ifdef USE_FLASHFS
613 case BLACKBOX_DEVICE_FLASH:
614 return flashfsIsEOF();
615 #endif // USE_FLASHFS
617 #ifdef USE_SDCARD
618 case BLACKBOX_DEVICE_SDCARD:
619 return afatfs_isFull();
620 #endif // USE_SDCARD
622 default:
623 return false;
627 bool isBlackboxDeviceWorking(void)
629 switch (blackboxConfig()->device) {
630 case BLACKBOX_DEVICE_SERIAL:
631 return blackboxPort != NULL;
633 #ifdef USE_SDCARD
634 case BLACKBOX_DEVICE_SDCARD:
635 return sdcard_isInserted() && sdcard_isFunctional() && (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_READY);
636 #endif
638 #ifdef USE_FLASHFS
639 case BLACKBOX_DEVICE_FLASH:
640 return flashfsIsReady();
641 #endif
643 default:
644 return false;
648 int32_t blackboxGetLogNumber(void)
650 switch (blackboxConfig()->device) {
651 #ifdef USE_SDCARD
652 case BLACKBOX_DEVICE_SDCARD:
653 return blackboxSDCard.largestLogFileNumber;
654 #endif
656 default:
657 return -1;
662 * Call once every loop iteration in order to maintain the global blackboxHeaderBudget with the number of bytes we can
663 * transmit this iteration.
665 void blackboxReplenishHeaderBudget(void)
667 int32_t freeSpace;
669 switch (blackboxConfig()->device) {
670 case BLACKBOX_DEVICE_SERIAL:
671 freeSpace = serialTxBytesFree(blackboxPort);
672 break;
673 #ifdef USE_FLASHFS
674 case BLACKBOX_DEVICE_FLASH:
675 freeSpace = flashfsGetWriteBufferFreeSpace();
676 break;
677 #endif
678 #ifdef USE_SDCARD
679 case BLACKBOX_DEVICE_SDCARD:
680 freeSpace = afatfs_getFreeBufferSpace();
681 break;
682 #endif
683 default:
684 freeSpace = 0;
686 blackboxHeaderBudget = MIN(MIN(freeSpace, blackboxHeaderBudget + blackboxMaxHeaderBytesPerIteration), BLACKBOX_MAX_ACCUMULATED_HEADER_BUDGET);
690 * You must call this function before attempting to write Blackbox header bytes to ensure that the write will not
691 * cause buffers to overflow. The number of bytes you can write is capped by the blackboxHeaderBudget. Calling this
692 * reservation function doesn't decrease blackboxHeaderBudget, so you must manually decrement that variable by the
693 * number of bytes you actually wrote.
695 * When the Blackbox device is FlashFS, a successful return code guarantees that no data will be lost if you write that
696 * many bytes to the device (i.e. FlashFS's buffers won't overflow).
698 * When the device is a serial port, a successful return code guarantees that Cleanflight's serial Tx buffer will not
699 * overflow, and the outgoing bandwidth is likely to be small enough to give the OpenLog time to absorb MicroSD card
700 * latency. However the OpenLog could still end up silently dropping data.
702 * Returns:
703 * BLACKBOX_RESERVE_SUCCESS - Upon success
704 * BLACKBOX_RESERVE_TEMPORARY_FAILURE - The buffer is currently too full to service the request, try again later
705 * BLACKBOX_RESERVE_PERMANENT_FAILURE - The buffer is too small to ever service this request
707 blackboxBufferReserveStatus_e blackboxDeviceReserveBufferSpace(int32_t bytes)
709 if (bytes <= blackboxHeaderBudget) {
710 return BLACKBOX_RESERVE_SUCCESS;
713 // Handle failure:
714 switch (blackboxConfig()->device) {
715 case BLACKBOX_DEVICE_SERIAL:
717 * One byte of the tx buffer isn't available for user data (due to its circular list implementation),
718 * hence the -1. Note that the USB VCP implementation doesn't use a buffer and has txBufferSize set to zero.
720 if (blackboxPort->txBufferSize && bytes > (int32_t) blackboxPort->txBufferSize - 1) {
721 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
723 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
725 #ifdef USE_FLASHFS
726 case BLACKBOX_DEVICE_FLASH:
727 if (bytes > (int32_t) flashfsGetWriteBufferSize()) {
728 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
731 if (bytes > (int32_t) flashfsGetWriteBufferFreeSpace()) {
733 * The write doesn't currently fit in the buffer, so try to make room for it. Our flushing here means
734 * that the Blackbox header writing code doesn't have to guess about the best time to ask flashfs to
735 * flush, and doesn't stall waiting for a flush that would otherwise not automatically be called.
737 flashfsFlushAsync(true);
739 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
740 #endif // USE_FLASHFS
742 #ifdef USE_SDCARD
743 case BLACKBOX_DEVICE_SDCARD:
744 // Assume that all writes will fit in the SDCard's buffers
745 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
746 #endif // USE_SDCARD
748 default:
749 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
753 int8_t blackboxGetLogFileNo(void)
755 #ifdef USE_BLACKBOX
756 #ifdef USE_SDCARD
757 // return current file number or -1
758 if (blackboxSDCard.state == BLACKBOX_SDCARD_READY_TO_LOG) {
759 return blackboxSDCard.largestLogFileNumber;
760 } else {
761 return -1;
763 #else
764 // will be implemented later for flash based storage
765 return -1;
766 #endif
767 #endif
769 #endif // BLACKBOX