Merge some betaflight changes into CF.
[betaflight.git] / src / main / blackbox / blackbox_io.c
blob03d15e8648fa407814a904afae26421acd1eddb4
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include <platform.h>
25 #include "build/build_config.h"
27 #include "common/maths.h"
28 #include "common/encoding.h"
30 #include "config/parameter_group.h"
32 #include "drivers/serial.h"
33 #include "drivers/gyro_sync.h"
34 #include "common/streambuf.h"
36 #include "fc/fc_serial.h"
38 #include "io/serial.h"
39 #include "msp/msp.h"
40 #include "msp/msp_serial.h"
42 #include "common/printf.h"
44 #include "io/flashfs.h"
45 #include "io/asyncfatfs/asyncfatfs.h"
47 #include "blackbox.h"
48 #include "blackbox_io.h"
50 #ifdef BLACKBOX
52 extern uint32_t targetPidLooptime; // FIXME dependency on pid.h
54 #define BLACKBOX_SERIAL_PORT_MODE MODE_TX
56 // How many bytes can we transmit per loop iteration when writing headers?
57 static uint8_t blackboxMaxHeaderBytesPerIteration;
59 // How many bytes can we write *this* iteration without overflowing transmit buffers or overstressing the OpenLog?
60 int32_t blackboxHeaderBudget;
62 static serialPort_t *blackboxPort = NULL;
63 static portSharing_e blackboxPortSharing;
65 #ifdef USE_SDCARD
67 static struct {
68 afatfsFilePtr_t logFile;
69 afatfsFilePtr_t logDirectory;
70 afatfsFinder_t logDirectoryFinder;
71 uint32_t largestLogFileNumber;
73 enum {
74 BLACKBOX_SDCARD_INITIAL,
75 BLACKBOX_SDCARD_WAITING,
76 BLACKBOX_SDCARD_ENUMERATE_FILES,
77 BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY,
78 BLACKBOX_SDCARD_READY_TO_CREATE_LOG,
79 BLACKBOX_SDCARD_READY_TO_LOG
80 } state;
81 } blackboxSDCard;
83 #endif
85 void blackboxWrite(uint8_t value)
87 switch (blackboxConfig()->device) {
88 #ifdef USE_FLASHFS
89 case BLACKBOX_DEVICE_FLASH:
90 flashfsWriteByte(value); // Write byte asynchronously
91 break;
92 #endif
93 #ifdef USE_SDCARD
94 case BLACKBOX_DEVICE_SDCARD:
95 afatfs_fputc(blackboxSDCard.logFile, value);
96 break;
97 #endif
98 case BLACKBOX_DEVICE_SERIAL:
99 default:
100 serialWrite(blackboxPort, value);
101 break;
105 static void _putc(void *p, char c)
107 (void)p;
108 blackboxWrite(c);
111 static int blackboxPrintfv(const char *fmt, va_list va)
113 return tfp_format(NULL, _putc, fmt, va);
117 //printf() to the blackbox serial port with no blocking shenanigans (so it's caller's responsibility to not write too fast!)
118 int blackboxPrintf(const char *fmt, ...)
120 va_list va;
122 va_start(va, fmt);
124 int written = blackboxPrintfv(fmt, va);
126 va_end(va);
128 return written;
132 * printf a Blackbox header line with a leading "H " and trailing "\n" added automatically. blackboxHeaderBudget is
133 * decreased to account for the number of bytes written.
135 void blackboxPrintfHeaderLine(const char *fmt, ...)
137 va_list va;
139 blackboxWrite('H');
140 blackboxWrite(' ');
142 va_start(va, fmt);
144 int written = blackboxPrintfv(fmt, va);
146 va_end(va);
148 blackboxWrite('\n');
150 blackboxHeaderBudget -= written + 3;
153 // Print the null-terminated string 's' to the blackbox device and return the number of bytes written
154 int blackboxPrint(const char *s)
156 int length;
157 const uint8_t *pos;
159 switch (blackboxConfig()->device) {
161 #ifdef USE_FLASHFS
162 case BLACKBOX_DEVICE_FLASH:
163 length = strlen(s);
164 flashfsWrite((const uint8_t*) s, length, false); // Write asynchronously
165 break;
166 #endif
168 #ifdef USE_SDCARD
169 case BLACKBOX_DEVICE_SDCARD:
170 length = strlen(s);
171 afatfs_fwrite(blackboxSDCard.logFile, (const uint8_t*) s, length); // Ignore failures due to buffers filling up
172 break;
173 #endif
175 case BLACKBOX_DEVICE_SERIAL:
176 default:
177 pos = (uint8_t*) s;
178 while (*pos) {
179 serialWrite(blackboxPort, *pos);
180 pos++;
183 length = pos - (uint8_t*) s;
184 break;
187 return length;
191 * Write an unsigned integer to the blackbox serial port using variable byte encoding.
193 void blackboxWriteUnsignedVB(uint32_t value)
195 //While this isn't the final byte (we can only write 7 bits at a time)
196 while (value > 127) {
197 blackboxWrite((uint8_t) (value | 0x80)); // Set the high bit to mean "more bytes follow"
198 value >>= 7;
200 blackboxWrite(value);
204 * Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding.
206 void blackboxWriteSignedVB(int32_t value)
208 //ZigZag encode to make the value always positive
209 blackboxWriteUnsignedVB(zigzagEncode(value));
212 void blackboxWriteSignedVBArray(int32_t *array, int count)
214 for (int i = 0; i < count; i++) {
215 blackboxWriteSignedVB(array[i]);
219 void blackboxWriteSigned16VBArray(int16_t *array, int count)
221 for (int i = 0; i < count; i++) {
222 blackboxWriteSignedVB(array[i]);
226 void blackboxWriteS16(int16_t value)
228 blackboxWrite(value & 0xFF);
229 blackboxWrite((value >> 8) & 0xFF);
233 * Write a 2 bit tag followed by 3 signed fields of 2, 4, 6 or 32 bits
235 void blackboxWriteTag2_3S32(int32_t *values)
237 static const int NUM_FIELDS = 3;
239 //Need to be enums rather than const ints if we want to switch on them (due to being C)
240 enum {
241 BITS_2 = 0,
242 BITS_4 = 1,
243 BITS_6 = 2,
244 BITS_32 = 3
247 enum {
248 BYTES_1 = 0,
249 BYTES_2 = 1,
250 BYTES_3 = 2,
251 BYTES_4 = 3
254 int x;
255 int selector = BITS_2, selector2;
258 * Find out how many bits the largest value requires to encode, and use it to choose one of the packing schemes
259 * below:
261 * Selector possibilities
263 * 2 bits per field ss11 2233,
264 * 4 bits per field ss00 1111 2222 3333
265 * 6 bits per field ss11 1111 0022 2222 0033 3333
266 * 32 bits per field sstt tttt followed by fields of various byte counts
268 for (x = 0; x < NUM_FIELDS; x++) {
269 //Require more than 6 bits?
270 if (values[x] >= 32 || values[x] < -32) {
271 selector = BITS_32;
272 break;
275 //Require more than 4 bits?
276 if (values[x] >= 8 || values[x] < -8) {
277 if (selector < BITS_6) {
278 selector = BITS_6;
280 } else if (values[x] >= 2 || values[x] < -2) { //Require more than 2 bits?
281 if (selector < BITS_4) {
282 selector = BITS_4;
287 switch (selector) {
288 case BITS_2:
289 blackboxWrite((selector << 6) | ((values[0] & 0x03) << 4) | ((values[1] & 0x03) << 2) | (values[2] & 0x03));
290 break;
291 case BITS_4:
292 blackboxWrite((selector << 6) | (values[0] & 0x0F));
293 blackboxWrite((values[1] << 4) | (values[2] & 0x0F));
294 break;
295 case BITS_6:
296 blackboxWrite((selector << 6) | (values[0] & 0x3F));
297 blackboxWrite((uint8_t)values[1]);
298 blackboxWrite((uint8_t)values[2]);
299 break;
300 case BITS_32:
302 * Do another round to compute a selector for each field, assuming that they are at least 8 bits each
304 * Selector2 field possibilities
305 * 0 - 8 bits
306 * 1 - 16 bits
307 * 2 - 24 bits
308 * 3 - 32 bits
310 selector2 = 0;
312 //Encode in reverse order so the first field is in the low bits:
313 for (x = NUM_FIELDS - 1; x >= 0; x--) {
314 selector2 <<= 2;
316 if (values[x] < 128 && values[x] >= -128) {
317 selector2 |= BYTES_1;
318 } else if (values[x] < 32768 && values[x] >= -32768) {
319 selector2 |= BYTES_2;
320 } else if (values[x] < 8388608 && values[x] >= -8388608) {
321 selector2 |= BYTES_3;
322 } else {
323 selector2 |= BYTES_4;
327 //Write the selectors
328 blackboxWrite((selector << 6) | selector2);
330 //And now the values according to the selectors we picked for them
331 for (x = 0; x < NUM_FIELDS; x++, selector2 >>= 2) {
332 switch (selector2 & 0x03) {
333 case BYTES_1:
334 blackboxWrite(values[x]);
335 break;
336 case BYTES_2:
337 blackboxWrite(values[x]);
338 blackboxWrite(values[x] >> 8);
339 break;
340 case BYTES_3:
341 blackboxWrite(values[x]);
342 blackboxWrite(values[x] >> 8);
343 blackboxWrite(values[x] >> 16);
344 break;
345 case BYTES_4:
346 blackboxWrite(values[x]);
347 blackboxWrite(values[x] >> 8);
348 blackboxWrite(values[x] >> 16);
349 blackboxWrite(values[x] >> 24);
350 break;
353 break;
358 * Write an 8-bit selector followed by four signed fields of size 0, 4, 8 or 16 bits.
360 void blackboxWriteTag8_4S16(int32_t *values)
363 //Need to be enums rather than const ints if we want to switch on them (due to being C)
364 enum {
365 FIELD_ZERO = 0,
366 FIELD_4BIT = 1,
367 FIELD_8BIT = 2,
368 FIELD_16BIT = 3
371 uint8_t selector, buffer;
372 int nibbleIndex;
373 int x;
375 selector = 0;
376 //Encode in reverse order so the first field is in the low bits:
377 for (x = 3; x >= 0; x--) {
378 selector <<= 2;
380 if (values[x] == 0) {
381 selector |= FIELD_ZERO;
382 } else if (values[x] < 8 && values[x] >= -8) {
383 selector |= FIELD_4BIT;
384 } else if (values[x] < 128 && values[x] >= -128) {
385 selector |= FIELD_8BIT;
386 } else {
387 selector |= FIELD_16BIT;
391 blackboxWrite(selector);
393 nibbleIndex = 0;
394 buffer = 0;
395 for (x = 0; x < 4; x++, selector >>= 2) {
396 switch (selector & 0x03) {
397 case FIELD_ZERO:
398 //No-op
399 break;
400 case FIELD_4BIT:
401 if (nibbleIndex == 0) {
402 //We fill high-bits first
403 buffer = values[x] << 4;
404 nibbleIndex = 1;
405 } else {
406 blackboxWrite(buffer | (values[x] & 0x0F));
407 nibbleIndex = 0;
409 break;
410 case FIELD_8BIT:
411 if (nibbleIndex == 0) {
412 blackboxWrite(values[x]);
413 } else {
414 //Write the high bits of the value first (mask to avoid sign extension)
415 blackboxWrite(buffer | ((values[x] >> 4) & 0x0F));
416 //Now put the leftover low bits into the top of the next buffer entry
417 buffer = values[x] << 4;
419 break;
420 case FIELD_16BIT:
421 if (nibbleIndex == 0) {
422 //Write high byte first
423 blackboxWrite(values[x] >> 8);
424 blackboxWrite(values[x]);
425 } else {
426 //First write the highest 4 bits
427 blackboxWrite(buffer | ((values[x] >> 12) & 0x0F));
428 // Then the middle 8
429 blackboxWrite(values[x] >> 4);
430 //Only the smallest 4 bits are still left to write
431 buffer = values[x] << 4;
433 break;
436 //Anything left over to write?
437 if (nibbleIndex == 1) {
438 blackboxWrite(buffer);
443 * Write `valueCount` fields from `values` to the Blackbox using signed variable byte encoding. A 1-byte header is
444 * written first which specifies which fields are non-zero (so this encoding is compact when most fields are zero).
446 * valueCount must be 8 or less.
448 void blackboxWriteTag8_8SVB(int32_t *values, int valueCount)
450 uint8_t header;
451 int i;
453 if (valueCount > 0) {
454 //If we're only writing one field then we can skip the header
455 if (valueCount == 1) {
456 blackboxWriteSignedVB(values[0]);
457 } else {
458 //First write a one-byte header that marks which fields are non-zero
459 header = 0;
461 // First field should be in low bits of header
462 for (i = valueCount - 1; i >= 0; i--) {
463 header <<= 1;
465 if (values[i] != 0) {
466 header |= 0x01;
470 blackboxWrite(header);
472 for (i = 0; i < valueCount; i++) {
473 if (values[i] != 0) {
474 blackboxWriteSignedVB(values[i]);
481 /** Write unsigned integer **/
482 void blackboxWriteU32(int32_t value)
484 blackboxWrite(value & 0xFF);
485 blackboxWrite((value >> 8) & 0xFF);
486 blackboxWrite((value >> 16) & 0xFF);
487 blackboxWrite((value >> 24) & 0xFF);
490 /** Write float value in the integer form **/
491 void blackboxWriteFloat(float value)
493 blackboxWriteU32(castFloatBytesToInt(value));
497 * If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
499 * Intended to be called regularly for the blackbox device to perform housekeeping.
501 void blackboxDeviceFlush(void)
503 switch (blackboxConfig()->device) {
504 #ifdef USE_FLASHFS
506 * This is our only output device which requires us to call flush() in order for it to write anything. The other
507 * devices will progressively write in the background without Blackbox calling anything.
509 case BLACKBOX_DEVICE_FLASH:
510 flashfsFlushAsync();
511 break;
512 #endif
514 default:
520 * If there is data waiting to be written to the blackbox device, attempt to write (a portion of) that now.
522 * Returns true if all data has been written to the device.
524 bool blackboxDeviceFlushForce(void)
526 switch (blackboxConfig()->device) {
527 case BLACKBOX_DEVICE_SERIAL:
528 // Nothing to speed up flushing on serial, as serial is continuously being drained out of its buffer
529 return isSerialTransmitBufferEmpty(blackboxPort);
531 #ifdef USE_FLASHFS
532 case BLACKBOX_DEVICE_FLASH:
533 return flashfsFlushAsync();
534 #endif
536 #ifdef USE_SDCARD
537 case BLACKBOX_DEVICE_SDCARD:
538 /* SD card will flush itself without us calling it, but we need to call flush manually in order to check
539 * if it's done yet or not!
541 return afatfs_flush();
542 #endif
544 default:
545 return false;
550 * Attempt to open the logging device. Returns true if successful.
552 bool blackboxDeviceOpen(void)
554 switch (blackboxConfig()->device) {
555 case BLACKBOX_DEVICE_SERIAL:
557 serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_BLACKBOX);
558 baudRate_e baudRateIndex;
559 portOptions_t portOptions = SERIAL_PARITY_NO | SERIAL_NOT_INVERTED;
561 if (!portConfig) {
562 return false;
565 blackboxPortSharing = determinePortSharing(portConfig, FUNCTION_BLACKBOX);
566 baudRateIndex = portConfig->baudRates[BAUDRATE_BLACKBOX];
568 if (baudRates[baudRateIndex] == 230400) {
570 * OpenLog's 230400 baud rate is very inaccurate, so it requires a larger inter-character gap in
571 * order to maintain synchronization.
573 portOptions |= SERIAL_STOPBITS_2;
574 } else {
575 portOptions |= SERIAL_STOPBITS_1;
578 blackboxPort = openSerialPort(portConfig->identifier, FUNCTION_BLACKBOX, NULL, baudRates[baudRateIndex],
579 BLACKBOX_SERIAL_PORT_MODE, portOptions);
582 * The slowest MicroSD cards have a write latency approaching 150ms. The OpenLog's buffer is about 900
583 * bytes. In order for its buffer to be able to absorb this latency we must write slower than 6000 B/s.
585 * So:
586 * Bytes per loop iteration = floor((looptime_ns / 1000000.0) * 6000)
587 * = floor((looptime_ns * 6000) / 1000000.0)
588 * = floor((looptime_ns * 3) / 500.0)
589 * = (looptime_ns * 3) / 500
591 blackboxMaxHeaderBytesPerIteration = constrain((targetPidLooptime * 3) / 500, 1, BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION);
593 return blackboxPort != NULL;
595 break;
596 #ifdef USE_FLASHFS
597 case BLACKBOX_DEVICE_FLASH:
598 if (flashfsGetSize() == 0 || isBlackboxDeviceFull()) {
599 return false;
602 blackboxMaxHeaderBytesPerIteration = BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION;
604 return true;
605 break;
606 #endif
607 #ifdef USE_SDCARD
608 case BLACKBOX_DEVICE_SDCARD:
609 if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL || afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_UNKNOWN || afatfs_isFull()) {
610 return false;
613 blackboxMaxHeaderBytesPerIteration = BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION;
615 return true;
616 break;
617 #endif
618 default:
619 return false;
624 * Close the Blackbox logging device immediately without attempting to flush any remaining data.
626 void blackboxDeviceClose(void)
628 switch (blackboxConfig()->device) {
629 case BLACKBOX_DEVICE_SERIAL:
630 // Since the serial port could be shared with other processes, we have to give it back here
631 closeSerialPort(blackboxPort);
632 blackboxPort = NULL;
635 * Normally this would be handled by mw.c, but since we take an unknown amount
636 * of time to shut down asynchronously, we're the only ones that know when to call it.
638 if (blackboxPortSharing == PORTSHARING_SHARED) {
639 mspSerialAllocatePorts();
641 break;
642 default:
647 #ifdef USE_SDCARD
649 static void blackboxLogDirCreated(afatfsFilePtr_t directory)
651 if (directory) {
652 blackboxSDCard.logDirectory = directory;
654 afatfs_findFirst(blackboxSDCard.logDirectory, &blackboxSDCard.logDirectoryFinder);
656 blackboxSDCard.state = BLACKBOX_SDCARD_ENUMERATE_FILES;
657 } else {
658 // Retry
659 blackboxSDCard.state = BLACKBOX_SDCARD_INITIAL;
663 static void blackboxLogFileCreated(afatfsFilePtr_t file)
665 if (file) {
666 blackboxSDCard.logFile = file;
668 blackboxSDCard.largestLogFileNumber++;
670 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_LOG;
671 } else {
672 // Retry
673 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
677 static void blackboxCreateLogFile()
679 uint32_t remainder = blackboxSDCard.largestLogFileNumber + 1;
681 char filename[13];
683 filename[0] = 'L';
684 filename[1] = 'O';
685 filename[2] = 'G';
687 for (int i = 7; i >= 3; i--) {
688 filename[i] = (remainder % 10) + '0';
689 remainder /= 10;
692 filename[8] = '.';
693 filename[9] = 'T';
694 filename[10] = 'X';
695 filename[11] = 'T';
696 filename[12] = 0;
698 blackboxSDCard.state = BLACKBOX_SDCARD_WAITING;
700 afatfs_fopen(filename, "as", blackboxLogFileCreated);
704 * Begin a new log on the SDCard.
706 * Keep calling until the function returns true (open is complete).
708 static bool blackboxSDCardBeginLog()
710 fatDirectoryEntry_t *directoryEntry;
712 doMore:
713 switch (blackboxSDCard.state) {
714 case BLACKBOX_SDCARD_INITIAL:
715 if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_READY) {
716 blackboxSDCard.state = BLACKBOX_SDCARD_WAITING;
718 afatfs_mkdir("logs", blackboxLogDirCreated);
720 break;
722 case BLACKBOX_SDCARD_WAITING:
723 // Waiting for directory entry to be created
724 break;
726 case BLACKBOX_SDCARD_ENUMERATE_FILES:
727 while (afatfs_findNext(blackboxSDCard.logDirectory, &blackboxSDCard.logDirectoryFinder, &directoryEntry) == AFATFS_OPERATION_SUCCESS) {
728 if (directoryEntry && !fat_isDirectoryEntryTerminator(directoryEntry)) {
729 // If this is a log file, parse the log number from the filename
730 if (
731 directoryEntry->filename[0] == 'L' && directoryEntry->filename[1] == 'O' && directoryEntry->filename[2] == 'G'
732 && directoryEntry->filename[8] == 'T' && directoryEntry->filename[9] == 'X' && directoryEntry->filename[10] == 'T'
734 char logSequenceNumberString[6];
736 memcpy(logSequenceNumberString, directoryEntry->filename + 3, 5);
737 logSequenceNumberString[5] = '\0';
739 blackboxSDCard.largestLogFileNumber = MAX((uint32_t) atoi(logSequenceNumberString), blackboxSDCard.largestLogFileNumber);
741 } else {
742 // We're done checking all the files on the card, now we can create a new log file
743 afatfs_findLast(blackboxSDCard.logDirectory);
745 blackboxSDCard.state = BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY;
746 goto doMore;
749 break;
751 case BLACKBOX_SDCARD_CHANGE_INTO_LOG_DIRECTORY:
752 // Change into the log directory:
753 if (afatfs_chdir(blackboxSDCard.logDirectory)) {
754 // We no longer need our open handle on the log directory
755 afatfs_fclose(blackboxSDCard.logDirectory, NULL);
756 blackboxSDCard.logDirectory = NULL;
758 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
759 goto doMore;
761 break;
763 case BLACKBOX_SDCARD_READY_TO_CREATE_LOG:
764 blackboxCreateLogFile();
765 break;
767 case BLACKBOX_SDCARD_READY_TO_LOG:
768 return true; // Log has been created!
771 // Not finished init yet
772 return false;
775 #endif
778 * Begin a new log (for devices which support separations between the logs of multiple flights).
780 * Keep calling until the function returns true (open is complete).
782 bool blackboxDeviceBeginLog(void)
784 switch (blackboxConfig()->device) {
785 #ifdef USE_SDCARD
786 case BLACKBOX_DEVICE_SDCARD:
787 return blackboxSDCardBeginLog();
788 #endif
789 default:
790 return true;
796 * Terminate the current log (for devices which support separations between the logs of multiple flights).
798 * retainLog - Pass true if the log should be kept, or false if the log should be discarded (if supported).
800 * Keep calling until this returns true
802 bool blackboxDeviceEndLog(bool retainLog)
804 #ifndef USE_SDCARD
805 (void) retainLog;
806 #endif
808 switch (blackboxConfig()->device) {
809 #ifdef USE_SDCARD
810 case BLACKBOX_DEVICE_SDCARD:
811 // Keep retrying until the close operation queues
812 if (
813 (retainLog && afatfs_fclose(blackboxSDCard.logFile, NULL))
814 || (!retainLog && afatfs_funlink(blackboxSDCard.logFile, NULL))
816 // Don't bother waiting the for the close to complete, it's queued now and will complete eventually
817 blackboxSDCard.logFile = NULL;
818 blackboxSDCard.state = BLACKBOX_SDCARD_READY_TO_CREATE_LOG;
819 return true;
821 return false;
822 #endif
823 default:
824 return true;
828 bool isBlackboxDeviceFull(void)
830 switch (blackboxConfig()->device) {
831 case BLACKBOX_DEVICE_SERIAL:
832 return false;
834 #ifdef USE_FLASHFS
835 case BLACKBOX_DEVICE_FLASH:
836 return flashfsIsEOF();
837 #endif
839 #ifdef USE_SDCARD
840 case BLACKBOX_DEVICE_SDCARD:
841 return afatfs_isFull();
842 #endif
844 default:
845 return false;
850 * Call once every loop iteration in order to maintain the global blackboxHeaderBudget with the number of bytes we can
851 * transmit this iteration.
853 void blackboxReplenishHeaderBudget()
855 int32_t freeSpace;
857 switch (blackboxConfig()->device) {
858 case BLACKBOX_DEVICE_SERIAL:
859 freeSpace = serialTxBytesFree(blackboxPort);
860 break;
861 #ifdef USE_FLASHFS
862 case BLACKBOX_DEVICE_FLASH:
863 freeSpace = flashfsGetWriteBufferFreeSpace();
864 break;
865 #endif
866 #ifdef USE_SDCARD
867 case BLACKBOX_DEVICE_SDCARD:
868 freeSpace = afatfs_getFreeBufferSpace();
869 break;
870 #endif
871 default:
872 freeSpace = 0;
875 blackboxHeaderBudget = MIN(MIN(freeSpace, blackboxHeaderBudget + blackboxMaxHeaderBytesPerIteration), BLACKBOX_MAX_ACCUMULATED_HEADER_BUDGET);
879 * You must call this function before attempting to write Blackbox header bytes to ensure that the write will not
880 * cause buffers to overflow. The number of bytes you can write is capped by the blackboxHeaderBudget. Calling this
881 * reservation function doesn't decrease blackboxHeaderBudget, so you must manually decrement that variable by the
882 * number of bytes you actually wrote.
884 * When the Blackbox device is FlashFS, a successful return code guarantees that no data will be lost if you write that
885 * many bytes to the device (i.e. FlashFS's buffers won't overflow).
887 * When the device is a serial port, a successful return code guarantees that Cleanflight's serial Tx buffer will not
888 * overflow, and the outgoing bandwidth is likely to be small enough to give the OpenLog time to absorb MicroSD card
889 * latency. However the OpenLog could still end up silently dropping data.
891 * Returns:
892 * BLACKBOX_RESERVE_SUCCESS - Upon success
893 * BLACKBOX_RESERVE_TEMPORARY_FAILURE - The buffer is currently too full to service the request, try again later
894 * BLACKBOX_RESERVE_PERMANENT_FAILURE - The buffer is too small to ever service this request
896 blackboxBufferReserveStatus_e blackboxDeviceReserveBufferSpace(int32_t bytes)
898 if (bytes <= blackboxHeaderBudget) {
899 return BLACKBOX_RESERVE_SUCCESS;
902 // Handle failure:
903 switch (blackboxConfig()->device) {
904 case BLACKBOX_DEVICE_SERIAL:
906 * One byte of the tx buffer isn't available for user data (due to its circular list implementation),
907 * hence the -1. Note that the USB VCP implementation doesn't use a buffer and has txBufferSize set to zero.
909 if (blackboxPort->txBufferSize && bytes > (int32_t) blackboxPort->txBufferSize - 1) {
910 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
913 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
915 #ifdef USE_FLASHFS
916 case BLACKBOX_DEVICE_FLASH:
917 if (bytes > (int32_t) flashfsGetWriteBufferSize()) {
918 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
921 if (bytes > (int32_t) flashfsGetWriteBufferFreeSpace()) {
923 * The write doesn't currently fit in the buffer, so try to make room for it. Our flushing here means
924 * that the Blackbox header writing code doesn't have to guess about the best time to ask flashfs to
925 * flush, and doesn't stall waiting for a flush that would otherwise not automatically be called.
927 flashfsFlushAsync();
930 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
931 #endif
933 #ifdef USE_SDCARD
934 case BLACKBOX_DEVICE_SDCARD:
935 // Assume that all writes will fit in the SDCard's buffers
936 return BLACKBOX_RESERVE_TEMPORARY_FAILURE;
937 #endif
939 default:
940 return BLACKBOX_RESERVE_PERMANENT_FAILURE;
944 #endif