Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3ddfb35
afatfs: move a shrunken freefile to the card's largest free block at …
MrScothh Sep 27, 2026
2926b97
afatfs: extend the freefile at boot over the free clusters that follo…
MrScothh Sep 27, 2026
e9a4c0b
afatfs: follow the FAT position when a cluster search skips the freefile
MrScothh Sep 27, 2026
c6115b0
afatfs: don't pre-erase a FAT sector that is only partly overwritten
MrScothh Sep 27, 2026
7d1262c
afatfs: retained cache sectors are not free buffer space
MrScothh Sep 27, 2026
664f7cf
afatfs: size the sector cache for the MCU family
MrScothh Sep 27, 2026
7cb044f
blackbox: continue an SD log in a new file when it can't grow and the…
MrScothh Sep 27, 2026
c8ce3ef
blackbox: send a split log's header several steps per iteration, with…
MrScothh Sep 27, 2026
57c1adc
afatfs, blackbox: a split never leaves an empty log to truncate, and …
MrScothh Sep 27, 2026
9f908bf
afatfs: keep the mount code out of the F7's ITCM
MrScothh Sep 28, 2026
f46fc85
afatfs: keep the mount code out of the F7's ITCM
MrScothh Sep 28, 2026
eeae2de
afatfs: keep the freefile refill out of the F7's ITCM
MrScothh Sep 28, 2026
dd22fd7
afatfs: a refill that fails to link or save its entry stops instead o…
MrScothh Sep 28, 2026
9da70af
afatfs: an F4 card on SPI keeps its cache in CCM whatever its size
MrScothh Sep 28, 2026
4d7f2b3
docs: what the onboard SD card does with its free space
MrScothh Sep 28, 2026
1747ab4
afatfs: shorter comment, and docs for the log split and the freefile
MrScothh Sep 28, 2026
c1eb20e
Merge maintenance-10.x into fix/afatfs-freefile-regrow
MrScothh Oct 6, 2026
b5651ca
Merge maintenance-10.x into feature/blackbox-sd-split
MrScothh Oct 6, 2026
0cf3c99
afatfs: regrow and move the freefile a block at a time, saving its di…
MrScothh Oct 7, 2026
f63952b
Merge fix/afatfs-freefile-regrow into feature/blackbox-sd-split
MrScothh Oct 7, 2026
99dc078
afatfs: write the freefile's FAT a sector at a time, growing from the…
MrScothh Oct 8, 2026
d655443
afatfs: let terrain read its files while the refill searches for the …
MrScothh Oct 8, 2026
537faed
Merge remote-tracking branch 'fork/fix/afatfs-freefile-regrow' into f…
MrScothh Oct 8, 2026
84e5a12
afatfs: chain an in-flight claim from its last FAT sector back
MrScothh Oct 8, 2026
ed03967
afatfs: a deleted file clears the latch that kept a full card from a …
MrScothh Oct 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/Blackbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ After downloading the log, be sure to erase the chip to make it ready for reuse

If you try to start recording a new flight when the dataflash is already full, Blackbox logging will be disabled and nothing will be recorded.

### Usage - Onboard SD card
Logs are `LOGxxxxx.TXT` files on the card. The card's free space is kept in a file named `FREESPAC.E`; at every boot it grows again over the space freed since, so logs deleted on a PC make room again after the next power cycle.

On targets with more than 512 KB of flash, a log that can't grow any further, because it reached 4 GB (the largest FAT32 file) or `FREESPAC.E` ran out while the card still has room, continues in a new file with its own header.

### Usage - Logging switch
If you're recording to an onboard flash chip, you probably want to disable Blackbox recording when not required in order to save storage space. To do this, you can add a Blackbox flight mode to one of your AUX channels on the Configurator's modes tab. Once you've added a mode, Blackbox will only log flight data when the mode is active.

Expand Down
44 changes: 43 additions & 1 deletion src/main/blackbox/blackbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,13 @@ static bool testBlackboxCondition(FlightLogFieldCondition condition)
return (blackboxConditionCache & position) != 0;
}

#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
// A new file after a split has no serial port to wait for
static bool blackboxSplitting;
#else
#define blackboxSplitting false
#endif

static void blackboxSetState(BlackboxState newState)
{
//Perform initial setup required for the new state
Expand All @@ -930,6 +937,9 @@ static void blackboxSetState(BlackboxState newState)
break;
case BLACKBOX_STATE_RUNNING:
blackboxSlowFrameIterationTimer = blackboxSInterval; //Force a slow frame to be written on the first iteration
#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
blackboxSplitting = false;
#endif
break;
case BLACKBOX_STATE_SHUTTING_DOWN:
xmitState.u.startTime = millis();
Expand Down Expand Up @@ -2329,10 +2339,34 @@ static void blackboxLogIteration(timeUs_t currentTimeUs)
blackboxDeviceFlush();
}

#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
static void blackboxUpdateState(timeUs_t currentTimeUs);

// Time per iteration a new file's header may take on top of the usual step
#define BLACKBOX_SPLIT_HEADER_US 50

/**
* Call each flight loop iteration to perform blackbox logging.
*/
void blackboxUpdate(timeUs_t currentTimeUs)
{
blackboxUpdateState(currentTimeUs);

// Every iteration spent on the new file's header is a gap in the log, so send it several steps at a time
const timeUs_t startUs = micros();
while (blackboxSplitting && blackboxState >= BLACKBOX_FIRST_HEADER_SENDING_STATE && blackboxState <= BLACKBOX_LAST_HEADER_SENDING_STATE
&& cmpTimeUs(micros(), startUs) < BLACKBOX_SPLIT_HEADER_US && blackboxDeviceHasRoomToSpare()) {
blackboxUpdateState(currentTimeUs);
}
}

static void blackboxUpdateState(timeUs_t currentTimeUs)
#else
/**
* Call each flight loop iteration to perform blackbox logging.
*/
void blackboxUpdate(timeUs_t currentTimeUs)
#endif
{
#ifdef USE_TERRAIN
if(blackboxConfig()->device == BLACKBOX_DEVICE_SDCARD){
Expand Down Expand Up @@ -2370,7 +2404,7 @@ void blackboxUpdate(timeUs_t currentTimeUs)
* Once the UART has had time to init, transmit the header in chunks so we don't overflow its transmit
* buffer, overflow the OpenLog's buffer, or keep the main loop busy for too long.
*/
if (millis() > xmitState.u.startTime + 100) {
if (blackboxSplitting || millis() > xmitState.u.startTime + 100) {
if (blackboxDeviceReserveBufferSpace(BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION) == BLACKBOX_RESERVE_SUCCESS) {
for (int i = 0; i < BLACKBOX_TARGET_HEADER_BUDGET_PER_ITERATION && blackboxHeader[xmitState.headerIndex] != '\0'; i++, xmitState.headerIndex++) {
blackboxWrite(blackboxHeader[xmitState.headerIndex]);
Expand Down Expand Up @@ -2477,6 +2511,14 @@ void blackboxUpdate(timeUs_t currentTimeUs)
break;
}

#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
// Can't grow but the card has room: close the log, it goes on in a new file
if ((blackboxState == BLACKBOX_STATE_RUNNING || blackboxState == BLACKBOX_STATE_PAUSED) && blackboxDeviceNeedsNewLog()) {
blackboxSplitting = true;
blackboxSetState(BLACKBOX_STATE_SHUTTING_DOWN);
}
#endif

// Did we run out of room on the device? Stop!
if (isBlackboxDeviceFull()) {
blackboxSetState(BLACKBOX_STATE_STOPPED);
Expand Down
30 changes: 29 additions & 1 deletion src/main/blackbox/blackbox_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ bool blackboxDeviceOpen(void)
#endif
#ifdef USE_SDCARD
case BLACKBOX_DEVICE_SDCARD:
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL || afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_UNKNOWN || afatfs_isFull()) {
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL || afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_UNKNOWN || isBlackboxDeviceFull()) {
return false;
}

Expand Down Expand Up @@ -432,7 +432,13 @@ static bool blackboxSDCardBeginLog(void)
doMore:
switch (blackboxSDCard.state) {
case BLACKBOX_SDCARD_INITIAL:
#ifdef USE_BLACKBOX_SDCARD_SPLIT
// A new file waits until the freefile has room for its first supercluster, unless no room can
// come: then it opens as without the option and the full card stops the log
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_READY && (afatfs_freeFileHasRoom() || !afatfs_freeFileCanContinue())) {
#else
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_READY) {
#endif
blackboxSDCard.state = BLACKBOX_SDCARD_WAITING;

if(afatfs_isCurrentDirRoot()){
Expand Down Expand Up @@ -579,8 +585,13 @@ bool isBlackboxDeviceFull(void)

#ifdef USE_SDCARD
case BLACKBOX_DEVICE_SDCARD:
#ifdef USE_BLACKBOX_SDCARD_SPLIT
// Only full once no new file can get room either
return afatfs_isFull() && !afatfs_freeFileCanContinue();
#else
return afatfs_isFull();
#endif
#endif

#if defined (SITL_BUILD)
case BLACKBOX_DEVICE_FILE:
Expand All @@ -592,6 +603,23 @@ bool isBlackboxDeviceFull(void)
}
}

#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
// The log file can't grow but the card has room for a new one
bool blackboxDeviceNeedsNewLog(void)
{
return blackboxConfig()->device == BLACKBOX_DEVICE_SDCARD && afatfs_isFull() && afatfs_freeFileCanContinue();
}

// Below this free cache space a new file's header goes back to one step per iteration: afatfs
// counts the sectors it keeps for open files as free
#define BLACKBOX_SDCARD_SPARE_BYTES 2048

bool blackboxDeviceHasRoomToSpare(void)
{
return afatfs_getFreeBufferSpace() >= BLACKBOX_SDCARD_SPARE_BYTES;
}
#endif

bool isBlackboxDeviceWorking(void)
{
switch (blackboxConfig()->device) {
Expand Down
4 changes: 4 additions & 0 deletions src/main/blackbox/blackbox_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ bool blackboxDeviceBeginLog(void);
bool blackboxDeviceEndLog(bool retainLog);

bool isBlackboxDeviceFull(void);
#if defined(USE_SDCARD) && defined(USE_BLACKBOX_SDCARD_SPLIT)
bool blackboxDeviceNeedsNewLog(void);
bool blackboxDeviceHasRoomToSpare(void);
#endif
bool isBlackboxDeviceWorking(void);
int32_t blackboxGetLogNumber(void);

Expand Down
Loading
Loading