#15692·betaflight

Autopilot Status Flags: AUTOPILOT_STOP[6] duplicates [7], the 100 failure sentinel collides with a real statusValue, and the decimal code cannot be annotated as flags

Author: haslinghuisCreated Sep 12, 2026Updated Sep 12, 2026

Summary

Four things about the autopilot "Status Flags" slots, found while regenerating the configurator's debug tables from the annotations (betaflight/betaflight-configurator#5520). All on master f5fb2717b8, all in flight/autopilot_multirotor.c unless noted.

They are grouped here because they share one root cause: statusValue is a hand-rolled decimal-additive code, not a bit field, and the failure paths overwrite it with sentinel numbers drawn from the same number line.

1. DEBUG_AUTOPILOT_STOP[6] and [7] are the same value

L1202-L1203:

c
DEBUG_SET(DEBUG_AUTOPILOT_STOP, 6, statusValue + (ap.isPosHoldBraking ? 1 : 0));  //!< Status Flags
DEBUG_SET(DEBUG_AUTOPILOT_STOP, 7, statusValue + (ap.isPosHoldBraking ? 1 : 0));  //!< Status Flags

Byte-identical expressions, identical label. The duplication repeats on both failure paths — L565-L566 (both 100) and L1010-L1011 (both 200) — so it is systematic rather than a one-line slip.

One of the mode's eight slots is spent on a copy. It reads like [7] was meant to hold something else and never got it.

2. DEBUG_AUTOPILOT_PID[7] mirrors those two, except on one path

DEBUG_AUTOPILOT_PID[7] is written with the same expression and the same sentinels (100 at L564, 200 at L1009, the normal value at L1194) — but the sensors-not-OK path in pos_hold_multirotor.c#L152 writes 333 to DEBUG_AUTOPILOT_PID[7] only:

c
// 333 traps the sensors-not-OK path
DEBUG_SET(DEBUG_AUTOPILOT_PID, 7, 333);  //!< Status Flags

So the three slots agree everywhere except there, where AUTOPILOT_STOP[6]/[7] keep whatever they held last. Anyone reading an AUTOPILOT_STOP log has no way to see the sensor dropout that an AUTOPILOT_PID log shows plainly, which rather defeats the point of duplicating the field into that mode.

3. The 100 sentinel collides with a legitimate statusValue

L1180-L1185:

c
int statusValue = 0;
if (ap.navActive)       statusValue += 10;
if (anchorOff)          statusValue += 20;
if (abortNavRequested)  statusValue += 100;
if (isPositionHeld)     statusValue += 3; // plus 1, ie 4,  if stopping
if (ap.sticksActive)    statusValue += 5;

abortNavRequested alone gives exactly 100 — the same number handlepositionControlFailure() writes as its sentinel. The two states are indistinguishable in a log.

200 and 333 are safely outside the 0..139 range the expression can produce, so only 100 is affected.

4. The code cannot be annotated, so the configurator shows a bare number

//!< Status Flags carries a label but no shape, because none fits: the value is neither a bit field (so [flags:...] is out) nor a small dense enumeration (so [enum:...] is out). It is decodable by hand — each contribution lands in its own decimal digit — but the configurator and blackbox viewer can only render, say, 133 and leave the user to work out navActive + anchorOff + isPositionHeld + braking.

The same applies to DEBUG_POSITION_NAV[7], (anchorOff ? 10 : 0) + (buildupClamped ? 1 : 0) at L1212 — two booleans that would be a two-bit field in any other debug mode.

Suggested fix

Make statusValue an actual bit field:

c
uint16_t statusFlags = 0;
if (ap.navActive)          statusFlags |= AP_STATUS_NAV_ACTIVE;
if (anchorOff)             statusFlags |= AP_STATUS_ANCHOR_OFF;
if (abortNavRequested)     statusFlags |= AP_STATUS_ABORT_NAV;
if (isPositionHeld)        statusFlags |= AP_STATUS_POSITION_HELD;
if (ap.sticksActive)       statusFlags |= AP_STATUS_STICKS_ACTIVE;
if (ap.isPosHoldBraking)   statusFlags |= AP_STATUS_BRAKING;

That makes the annotation express it directly —

c
DEBUG_SET(DEBUG_AUTOPILOT_PID, 7, statusFlags);  //!< Status Flags [flags:Nav Active|Anchor Off|Abort Nav|Position Held|Sticks Active|Braking]

— and the configurator will decode each bit by name instead of printing a total. DEBUG_POSITION_NAV[7] wants the same treatment with [flags:Anchor Off|Buildup Clamped].

The failure states then need bits of their own (AP_STATUS_CONTROL_FAILURE, AP_STATUS_FORCE_PITCH_FORWARD, AP_STATUS_SENSORS_NOT_OK) rather than sentinel totals, which removes the 100 collision and lets a failure frame keep showing the rest of the state instead of erasing it.

And DEBUG_AUTOPILOT_STOP[7] should either get a distinct quantity or be dropped, rather than duplicating [6].

Related: #15598 (boolean/enum metadata for debug fields), #15691, #15594, #15610.