mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-16 12:55:19 +03:00
Add resume event to allow clean log decoding, add documentation
This commit is contained in:
parent
01632998a3
commit
53860e461c
5 changed files with 86 additions and 35 deletions
|
@ -230,6 +230,14 @@ 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 - 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.
|
||||
|
||||
A log header will always be recorded at arming time, even if logging is paused. You can freely pause and resume logging
|
||||
while in flight.
|
||||
|
||||
## Converting logs to CSV or PNG
|
||||
After your flights, you'll have a series of flight log files with a .TXT extension. You'll need to decode these with
|
||||
the `blackbox_decode` tool to create CSV (comma-separated values) files for analysis, or render them into a series of PNG
|
||||
|
|
|
@ -256,6 +256,7 @@ typedef enum BlackboxState {
|
|||
BLACKBOX_STATE_SEND_GPS_G_HEADER,
|
||||
BLACKBOX_STATE_SEND_SLOW_HEADER,
|
||||
BLACKBOX_STATE_SEND_SYSINFO,
|
||||
BLACKBOX_STATE_PAUSED,
|
||||
BLACKBOX_STATE_RUNNING,
|
||||
BLACKBOX_STATE_SHUTTING_DOWN
|
||||
} BlackboxState;
|
||||
|
@ -456,9 +457,6 @@ static void blackboxSetState(BlackboxState newState)
|
|||
xmitState.headerIndex = 0;
|
||||
break;
|
||||
case BLACKBOX_STATE_RUNNING:
|
||||
blackboxIteration = 0;
|
||||
blackboxPFrameIndex = 0;
|
||||
blackboxIFrameIndex = 0;
|
||||
blackboxSlowFrameIterationTimer = SLOW_FRAME_INTERVAL; //Force a slow frame to be written on the first iteration
|
||||
break;
|
||||
case BLACKBOX_STATE_SHUTTING_DOWN:
|
||||
|
@ -773,7 +771,6 @@ static void validateBlackboxConfig()
|
|||
*/
|
||||
void startBlackbox(void)
|
||||
{
|
||||
blackboxModeActivationConditionPresent = isModeActivationConditionPresent(currentProfile->modeActivationConditions, BOXBLACKBOX);
|
||||
if (blackboxState == BLACKBOX_STATE_STOPPED) {
|
||||
validateBlackboxConfig();
|
||||
|
||||
|
@ -799,6 +796,12 @@ void startBlackbox(void)
|
|||
*/
|
||||
blackboxBuildConditionCache();
|
||||
|
||||
blackboxModeActivationConditionPresent = isModeActivationConditionPresent(currentProfile->modeActivationConditions, BOXBLACKBOX);
|
||||
|
||||
blackboxIteration = 0;
|
||||
blackboxPFrameIndex = 0;
|
||||
blackboxIFrameIndex = 0;
|
||||
|
||||
/*
|
||||
* Record the beeper's current idea of the last arming beep time, so that we can detect it changing when
|
||||
* it finally plays the beep for this arming event.
|
||||
|
@ -814,7 +817,7 @@ void startBlackbox(void)
|
|||
*/
|
||||
void finishBlackbox(void)
|
||||
{
|
||||
if (blackboxState == BLACKBOX_STATE_RUNNING) {
|
||||
if (blackboxState == BLACKBOX_STATE_RUNNING || blackboxState == BLACKBOX_STATE_PAUSED) {
|
||||
blackboxLogEvent(FLIGHT_LOG_EVENT_LOG_END, NULL);
|
||||
|
||||
blackboxSetState(BLACKBOX_STATE_SHUTTING_DOWN);
|
||||
|
@ -1102,7 +1105,8 @@ static bool blackboxWriteSysinfo()
|
|||
*/
|
||||
void blackboxLogEvent(FlightLogEvent event, flightLogEventData_t *data)
|
||||
{
|
||||
if (blackboxState != BLACKBOX_STATE_RUNNING) {
|
||||
// Only allow events to be logged after headers have been written
|
||||
if (!(blackboxState == BLACKBOX_STATE_RUNNING || blackboxState == BLACKBOX_STATE_PAUSED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1144,6 +1148,10 @@ void blackboxLogEvent(FlightLogEvent event, flightLogEventData_t *data)
|
|||
blackboxWriteSignedVB(data->inflightAdjustment.newValue);
|
||||
}
|
||||
break;
|
||||
case FLIGHT_LOG_EVENT_LOGGING_RESUME:
|
||||
blackboxWriteUnsignedVB(data->loggingResume.logIteration);
|
||||
blackboxWriteUnsignedVB(data->loggingResume.currentTime);
|
||||
break;
|
||||
case FLIGHT_LOG_EVENT_LOG_END:
|
||||
blackboxPrint("End of log");
|
||||
blackboxWrite(0);
|
||||
|
@ -1178,34 +1186,51 @@ static bool blackboxShouldLogPFrame(uint32_t pFrameIndex)
|
|||
return (pFrameIndex + masterConfig.blackbox_rate_num - 1) % masterConfig.blackbox_rate_denom < masterConfig.blackbox_rate_num;
|
||||
}
|
||||
|
||||
static bool blackboxShouldLogIFrame() {
|
||||
return blackboxPFrameIndex == 0;
|
||||
}
|
||||
|
||||
// Called once every FC loop in order to keep track of how many FC loop iterations have passed
|
||||
static void blackboxAdvanceIterationTimers()
|
||||
{
|
||||
blackboxSlowFrameIterationTimer++;
|
||||
blackboxIteration++;
|
||||
blackboxPFrameIndex++;
|
||||
|
||||
if (blackboxPFrameIndex == BLACKBOX_I_INTERVAL) {
|
||||
blackboxPFrameIndex = 0;
|
||||
blackboxIFrameIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Called once every FC loop in order to log the current state
|
||||
static void blackboxLogIteration(bool writeFrames)
|
||||
static void blackboxLogIteration()
|
||||
{
|
||||
// Write a keyframe every BLACKBOX_I_INTERVAL frames so we can resynchronise upon missing frames
|
||||
if (blackboxPFrameIndex == 0) {
|
||||
if (blackboxShouldLogIFrame()) {
|
||||
/*
|
||||
* Don't log a slow frame if the slow data didn't change ("I" frames are already large enough without adding
|
||||
* an additional item to write at the same time)
|
||||
*/
|
||||
if (writeFrames) {
|
||||
writeSlowFrameIfNeeded(false);
|
||||
loadMainState();
|
||||
writeIntraframe();
|
||||
}
|
||||
writeSlowFrameIfNeeded(false);
|
||||
|
||||
loadMainState();
|
||||
writeIntraframe();
|
||||
} else {
|
||||
blackboxCheckAndLogArmingBeep();
|
||||
|
||||
if (blackboxShouldLogPFrame(blackboxPFrameIndex) && writeFrames) {
|
||||
/*
|
||||
if (blackboxShouldLogPFrame(blackboxPFrameIndex)) {
|
||||
/*
|
||||
* We assume that slow frames are only interesting in that they aid the interpretation of the main data stream.
|
||||
* So only log slow frames during loop iterations where we log a main frame.
|
||||
*/
|
||||
writeSlowFrameIfNeeded(true);
|
||||
|
||||
loadMainState();
|
||||
writeInterframe();
|
||||
}
|
||||
#ifdef GPS
|
||||
if (feature(FEATURE_GPS) && writeFrames) {
|
||||
if (feature(FEATURE_GPS)) {
|
||||
/*
|
||||
* If the GPS home point has been updated, or every 128 intraframes (~10 seconds), write the
|
||||
* GPS home position.
|
||||
|
@ -1229,15 +1254,6 @@ static void blackboxLogIteration(bool writeFrames)
|
|||
|
||||
//Flush every iteration so that our runtime variance is minimized
|
||||
blackboxDeviceFlush();
|
||||
|
||||
blackboxSlowFrameIterationTimer++;
|
||||
blackboxIteration++;
|
||||
blackboxPFrameIndex++;
|
||||
|
||||
if (blackboxPFrameIndex == BLACKBOX_I_INTERVAL) {
|
||||
blackboxPFrameIndex = 0;
|
||||
blackboxIFrameIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1308,18 +1324,33 @@ void handleBlackbox(void)
|
|||
blackboxSetState(BLACKBOX_STATE_RUNNING);
|
||||
}
|
||||
break;
|
||||
case BLACKBOX_STATE_PAUSED:
|
||||
// Only allow resume to occur during an I-frame iteration, so that we have an "I" base to work from
|
||||
if (IS_RC_MODE_ACTIVE(BOXBLACKBOX) && blackboxShouldLogIFrame()) {
|
||||
// Write a log entry so the decoder is aware that our large time/iteration skip is intended
|
||||
flightLogEvent_loggingResume_t resume;
|
||||
|
||||
resume.logIteration = blackboxIteration;
|
||||
resume.currentTime = currentTime;
|
||||
|
||||
blackboxLogEvent(FLIGHT_LOG_EVENT_LOGGING_RESUME, (flightLogEventData_t *) &resume);
|
||||
blackboxSetState(BLACKBOX_STATE_RUNNING);
|
||||
|
||||
blackboxLogIteration();
|
||||
}
|
||||
|
||||
// Keep the logging timers ticking so our log iteration continues to advance
|
||||
blackboxAdvanceIterationTimers();
|
||||
break;
|
||||
case BLACKBOX_STATE_RUNNING:
|
||||
// On entry to this state, blackboxIteration, blackboxPFrameIndex and blackboxIFrameIndex are reset to 0
|
||||
if (blackboxModeActivationConditionPresent) {
|
||||
if (IS_RC_MODE_ACTIVE(BOXBLACKBOX)) {
|
||||
blackboxLogIteration(true);
|
||||
} else {
|
||||
// Log only first I frame
|
||||
blackboxLogIteration(blackboxIteration == 0);
|
||||
}
|
||||
if (blackboxModeActivationConditionPresent && !IS_RC_MODE_ACTIVE(BOXBLACKBOX)) {
|
||||
blackboxSetState(BLACKBOX_STATE_PAUSED);
|
||||
} else {
|
||||
blackboxLogIteration(true);
|
||||
blackboxLogIteration();
|
||||
}
|
||||
|
||||
blackboxAdvanceIterationTimers();
|
||||
break;
|
||||
case BLACKBOX_STATE_SHUTTING_DOWN:
|
||||
//On entry of this state, startTime is set and a flush is performed
|
||||
|
|
|
@ -107,6 +107,7 @@ typedef enum FlightLogEvent {
|
|||
FLIGHT_LOG_EVENT_AUTOTUNE_CYCLE_RESULT = 11,
|
||||
FLIGHT_LOG_EVENT_AUTOTUNE_TARGETS = 12,
|
||||
FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT = 13,
|
||||
FLIGHT_LOG_EVENT_LOGGING_RESUME = 14,
|
||||
FLIGHT_LOG_EVENT_LOG_END = 255
|
||||
} FlightLogEvent;
|
||||
|
||||
|
@ -147,6 +148,11 @@ typedef struct flightLogEvent_inflightAdjustment_t {
|
|||
float newFloatValue;
|
||||
} flightLogEvent_inflightAdjustment_t;
|
||||
|
||||
typedef struct flightLogEvent_loggingResume_t {
|
||||
uint32_t logIteration;
|
||||
uint32_t currentTime;
|
||||
} flightLogEvent_loggingResume_t;
|
||||
|
||||
typedef union flightLogEventData_t
|
||||
{
|
||||
flightLogEvent_syncBeep_t syncBeep;
|
||||
|
@ -154,6 +160,7 @@ typedef union flightLogEventData_t
|
|||
flightLogEvent_autotuneCycleResult_t autotuneCycleResult;
|
||||
flightLogEvent_autotuneTargets_t autotuneTargets;
|
||||
flightLogEvent_inflightAdjustment_t inflightAdjustment;
|
||||
flightLogEvent_loggingResume_t loggingResume;
|
||||
} flightLogEventData_t;
|
||||
|
||||
typedef struct flightLogEvent_t
|
||||
|
|
|
@ -316,8 +316,12 @@ bool isModeActivationConditionPresent(modeActivationCondition_t *modeActivationC
|
|||
|
||||
for (index = 0; index < MAX_MODE_ACTIVATION_CONDITION_COUNT; index++) {
|
||||
modeActivationCondition_t *modeActivationCondition = &modeActivationConditions[index];
|
||||
if (modeActivationCondition->modeId == modeId && IS_RANGE_USABLE(&modeActivationCondition->range)) return true;
|
||||
|
||||
if (modeActivationCondition->modeId == modeId && IS_RANGE_USABLE(&modeActivationCondition->range)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -680,7 +680,6 @@ void mspInit(serialConfig_t *serialConfig)
|
|||
activeBoxIds[activeBoxIdCount++] = BOXSONAR;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SERVOS
|
||||
if (masterConfig.mixerMode == MIXER_CUSTOM_AIRPLANE) {
|
||||
activeBoxIds[activeBoxIdCount++] = BOXSERVO1;
|
||||
|
@ -688,11 +687,13 @@ void mspInit(serialConfig_t *serialConfig)
|
|||
activeBoxIds[activeBoxIdCount++] = BOXSERVO3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLACKBOX
|
||||
if (feature(FEATURE_BLACKBOX)){
|
||||
activeBoxIds[activeBoxIdCount++] = BOXBLACKBOX;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(mspPorts, 0x00, sizeof(mspPorts));
|
||||
mspAllocateSerialPorts(serialConfig);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue