Skip to content

Merge maintenance-9.x into maintenance-10.x (conflict resolution)#11512

Merged
sensei-hacker merged 79 commits intoiNavFlight:maintenance-10.xfrom
sensei-hacker:merge-9x-into-10x
Apr 25, 2026
Merged

Merge maintenance-9.x into maintenance-10.x (conflict resolution)#11512
sensei-hacker merged 79 commits intoiNavFlight:maintenance-10.xfrom
sensei-hacker:merge-9x-into-10x

Conversation

@sensei-hacker
Copy link
Copy Markdown
Member

@sensei-hacker sensei-hacker commented Apr 25, 2026

Replaces #11509 with merge conflicts resolved.

Forward-ports all maintenance-9.x changes into maintenance-10.x.

File Resolution
docs/development/msp/inav_enums.json Accepted maintenance-10.x (new build+enums wrapper structure)
docs/development/msp/msp_messages.json Accepted maintenance-10.x (new version+messages wrapper; 4 messages removed from 9.x were intentionally superseded in 10.x)
docs/development/msp/msp_messages.checksum Deleted — versioning moved into msp_messages.json version field in 10.x
docs/development/msp/rev Deleted — same reason
docs/development/msp/README.md Accepted maintenance-10.x (proper regeneration/versioning docs replace simple rev counter)
docs/development/msp/gen_docs.sh Accepted maintenance-10.x (removed checksum block that 9.x re-added)
src/main/fc/fc_msp.c Kept both: MSP2_INAV_SET_AUX_RC from 9.x AND MSP2_INAV_FLIGHT_AXIS_ANGLE_OVERRIDE/RATE_OVERRIDE from 10.x

Closes #11509

gismo2004 and others added 30 commits December 18, 2025 12:07
This commit fixes the critical bugs that caused PR iNavFlight#11025 to be reverted
(PR iNavFlight#11139). The original implementation caused telemetry stream corruption
by emitting malformed frames when sensors were unavailable.

Root Cause:
The original PR scheduled telemetry frames unconditionally (if feature
compiled in) but frame functions only wrote data when sensors were available.
This resulted in frames containing only [SYNC][CRC] instead of the proper
[SYNC][LENGTH][TYPE][PAYLOAD][CRC] structure, corrupting the CRSF protocol
stream and breaking ALL telemetry (not just new frames).

Fixes Implemented:

1. RPM Frame (Bug #1 - CRITICAL):
   - Added conditional scheduling: only schedule if ESC_SENSOR_ENABLED
     and motorCount > 0
   - Added protocol limit enforcement: max 19 RPM values per CRSF spec
   - Location: src/main/telemetry/crsf.c:705-707, 337-343

2. Temperature Frame (Bug #2 - CRITICAL):
   - Added conditional scheduling: only schedule if temperature sources
     are actually available (ESC sensors OR temperature sensors)
   - Added bounds checking: prevent buffer overflow beyond 20 temperatures
   - Location: src/main/telemetry/crsf.c:709-732, 361-381

3. Buffer Overflow Protection (Bug #4):
   - Added MAX_CRSF_TEMPS constant and bounds checks in loops
   - Prevents array overflow if >20 temperature sources configured
   - Location: src/main/telemetry/crsf.c:361, 368, 376

4. Protocol Limit Enforcement (Bug #5):
   - Added MAX_CRSF_RPM_VALUES constant (19 per CRSF spec)
   - Clamp motorCount to protocol limit before sending
   - Location: src/main/telemetry/crsf.c:337, 342-344

Implementation Pattern:
Follows the GPS frame pattern:
  ✓ Conditional scheduling - only schedule if sensor available
  ✓ Unconditional writing - always write complete frame data when called

Testing:
- Code compiles successfully (verified with SITL build)
- No syntax errors or warnings
- All fixes follow existing code patterns in crsf.c

Related Issues:
- Original PR: iNavFlight#11025 (merged Nov 28, 2025, reverted same day)
- Revert PR: iNavFlight#11139
- Investigation: claude/developer/sent/pr11025-root-cause-analysis.md

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Correct the SPI register address masking in busWriteBuf() to clear the
MSB instead of setting it. For SPI protocol, the MSB indicates read (1)
or write (0) operations. Write operations should use (reg & 0x7F) to
clear the MSB, not (reg | 0x80) which sets it.

This matches the correct implementation in busWrite() at line 318 which
uses (reg & 0x7F) for write operations.

Note: This bug affects theoretical future SPI devices using buffer writes.
Current devices using busWriteBuf() are all I2C-based (VL53L0X, VL53L1X,
MLX90393, TERARANGER_EVO, US42 rangefinders) and are unaffected.

Fixes iNavFlight#10674
STM32F722-based target for the original (discontinued) Nexus,
distinct from the Nexus-X/XR (NEXUSX target). Pin mapping derived
from Rotorflight NEXUS_F7 dump and verified on hardware.

Key hardware support:
- ICM-42688-P IMU on SPI1 (CW90 alignment, EXTI PA15)
- SPL06 barometer on I2C1 (PB8/PB9, separate from external I2C2)
- W25N01G 128MB blackbox flash on SPI2
- 5 servo/motor outputs (S1-S4 + M1), expandable to 7
- UART4 with TX/RX swap for CRSF receiver on Port A
- UART1 on PA9/PA10 (not PB6/PB7 as on Nexus-X/XR)

Also adds USE_UART4_SWAP support in serial_uart_hal.c for the
STM32 HAL advanced UART pin swap feature.
GPS3DspeedFiltered was computed every PID cycle (1 kHz) from
gpsSol.velNED[], which only changes when the GPS task delivers a new
fix (~10 Hz). Move the sqrt and pt1 filter update into
imuCalculateTurnRateacceleration(), gate them on gpsHeartbeat change,
and make the filter state a static local. The variable is only
consumed in that function (fixed-wing + GPS-trustworthy path), so the
module-level FASTRAM variables and the imuInit() reset are also removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Five cycle-saving changes to imuMahonyAHRSupdate(), which accounts for
~205 µs (30%) of the PID loop on RP2350.  Each change is safe on all
targets; the gains are proportionally smaller on F7/H7 where the function
already lives in ITCM RAM.

1. Replace quaternionRotateVector({0,0,1}) with rMat[2][*] reads.
   imuComputeRotationMatrix() is called at the end of every invocation and
   keeps rMat in sync with orientation.  Rotating the constant gravity
   vector EF→BF yields exactly the third row of rMat, so three float loads
   replace ~56 floating-point multiply/add operations.

2. Eliminate sqrt() from the Taylor-series threshold.
   Original: thetaMagnitudeSq < sqrt(24e-6).
   Squaring both sides (both non-negative) gives the equivalent condition
   thetaMagnitudeSq² < 24e-6 with no sqrt call.

3. First-order Newton quaternion renormalization replaces quaternionNormalize()
   (sqrt + 4 divides, ~35 cycles) with scale = (3 - normSq) * 0.5 (~14 cycles).
   At 1 kHz the per-step drift |ε| < 1e-6, making the O(ε²) error < 1e-12.
   imuCheckAndResetOrientationQuaternion() remains as the catastrophic-failure
   safety net.

4. Precompute the anti-windup i_limit in imuConfigure() (called only on
   settings save).  The hot path now reads a single float instead of
   performing an add, a multiply, and a divide every PID cycle.
   Adds dcm_i_limit to imuRuntimeConfig_t and imuConfigure().

5. Reduce prevOrientation snapshot frequency from every PID cycle to
   every 100 cycles (~100 ms at 1 kHz).  The snapshot is only used by
   the fault-recovery path which should never fire in normal flight;
   16 bytes of unnecessary SRAM write every ms is not justified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Address hardware testing feedback from daijoubu:
- VBAT_SCALE_DEFAULT 1100 → 320 (hardware-verified)
- Port C connector pinout: pin 3 is SDA/TX (PB11), pin 4 is SCL/RX (PB10)
- Clarify OG Nexus has no EXT-V input (Vin ADC only, unlike X/XR)
- Update verification checklist with confirmed test results

Co-Authored-By: Joshua Perry <josh@6bit.com>
The CW90 value was taken directly from the Rotorflight NEXUS_F7 target,
but Rotorflight does not enforce arrow-forward as the board reference
orientation. The Rotorflight CW90 was calibrated to an arbitrary
mounting, not the case arrow. iNAV convention is arrow = forward,
which requires CW180 on this hardware.

Same root cause as the NEXUSX fix in iNavFlight#11338 / iNavFlight#11325.

Co-Authored-By: Joshua Perry <josh@6bit.com>
FrSky F405 flight controller based on STM32F405RGT6.

Hardware: IIM-42688P gyro (SPI1), AT7456E OSD (SPI2), SD card (SPI3),
SPL06 barometer (I2C1), 9 motor outputs, hardware SBUS inverter on UART2,
LED strip on PA15. S7/S8 use TIM12 (PWM only, no DShot).
- Fix UART5_RX: PD12 → PD2 (only valid pin for UART5_RX on STM32F405)
- Move SPI3 to PB3/PB4/PB5, freeing PC10/PC11/PC12 for UART3 and UART5_TX
- Move UART3 to PC10/PC11 (was conflicting with I2C2 on PB10/PB11)
- Fix UART4_RX: PC5 → PA1 (PC5 is shared with RSSI ADC)
- Re-enable I2C2 on PB10/PB11 (now free after UART3 move)
- Add TARGET_IO_PORTD for PD2 (UART5_RX)
- Update SERIAL_PORT_COUNT to 7 (includes UART5)
- Remove config.c: UART2 has both standard and hardware-inverted SBUS pads
- Change TARGET_BOARD_IDENTIFIER from "H743" to "BB43" (unique 4-char ID)
- Remove BEEPER_PWM_FREQUENCY (no matching DEF_TIM entry)
- Remove USE_SOFTSERIAL1 (unnecessary with 8 hardware UARTs + VCP)
- Update SERIAL_PORT_COUNT from 9 to 8
- Remove beeper PWM and softserial timer entries from target.c
- Fix trailing whitespace on DEF_TIM S3 line
Updated instructions to reflect the use of the maintenance branch instead of master for cloning and merging.
…ch-7

Update branch references from master to maintenance
Adds three new write-only MSP2 commands that allow a ground control
station to interact with an active INAV navigation session without
requiring direct RC transmitter input:

  MSP2_INAV_SET_WP_INDEX (0x2221)
    Jump to a specific waypoint during an active WP mission.
    Payload: U8 wp_index (0-based, relative to mission start waypoint).
    Preconditions: aircraft must be armed and NAV_WP_MODE must be active.
    Transitions any active waypoint FSM state back to PRE_ACTION so
    INAV re-initialises navigation for the new target waypoint.

  MSP2_INAV_SET_ALT_TARGET (0x2222)
    Set a new target altitude while altitude-controlled navigation is active.
    Payload: I32 altitude_cm (centimetres, relative to home).
    Preconditions: aircraft must be armed and NAV_CTL_ALT must be active.
    Calls updateClimbRateToAltitudeController() which works for both
    multicopter and fixed-wing platforms.

  MSP2_INAV_SET_CRUISE_HEADING (0x2223)
    Set the heading target while Cruise or Course Hold mode is active.
    Payload: I32 heading_centidegrees (0–35999).
    Preconditions: aircraft must be armed and NAV_COURSE_HOLD_MODE must
    be active. Sets both posControl.cruise.course and previousCourse to
    prevent spurious heading adjustments on the next control cycle.

Implementation details:
  - New FSM event NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_JUMP aliases
    NAV_FSM_EVENT_STATE_SPECIFIC_4 (safe: WP and RTH states never
    overlap so the same underlying integer can be reused in both groups).
  - FSM transitions added for PRE_ACTION, IN_PROGRESS, REACHED,
    HOLD_TIME and FINISHED states, all routing to PRE_ACTION.
  - Three new public functions declared in navigation.h and implemented
    in navigation.c: navSetActiveWaypointIndex(), navSetDesiredAltitude(),
    navSetCruiseHeading().
  - MSP handlers added in fc_msp.c; all return MSP_RESULT_ERROR if the
    aircraft is not in a compatible state.
…lementation

The set-altitude functionality is already covered by a more mature existing
implementation in INAV. Remove the MSP2_INAV_SET_ALT_TARGET command added in
the previous commit, keeping only MSP2_INAV_SET_WP_INDEX (0x2221) and
MSP2_INAV_SET_CRUISE_HEADING (0x2223).

Removes: define in msp_protocol_v2_inav.h, navSetDesiredAltitude() in
navigation.c/.h, the MSP handler in fc_msp.c, and the docs section.
Fix initSharedMsp() to initialize the response buffer as empty instead
of setting it to the full buffer size. This was causing the response-
pending check in handleMspFrame() to incorrectly detect a pending
response after every buffer reinitialization.

Root cause: initSharedMsp() set responsePacket->buf.end to
responseBuffer + sizeof(mspTxBuffer), putting the buffer in writer mode
with sbufBytesRemaining() returning the full buffer size (e.g. 512).
The response-pending check in handleMspFrame() interpreted this as
unsent response data and reset mspStarted to 0. This triggered another
call to initSharedMsp(), which reset the buffer to full size again,
creating a permanent cycle that dropped every continuation frame.

The response-pending check itself is correct and necessary: SmartPort
is half-duplex, so new request assembly must be blocked while a
response is still being sent. The bug was that initSharedMsp()
corrupted the buffer state that the check relies on.

The fix changes initSharedMsp() to set buf.end = buf.ptr (empty
reader), so sbufBytesRemaining() returns 0 when no response is
actually pending. processMspPacket() already sets up the response
buffer in writer mode before processing, so this change is safe.

Impact: all MSPv1/MSPv2 requests with payload requiring more than one
telemetry frame were silently dropped over SmartPort, CRSF, and FPort
MSP passthrough. Only zero-payload single-frame requests succeeded.

Tested on MATEKF765 with SmartPort MSP passthrough.
sensei-hacker and others added 23 commits April 11, 2026 15:39
Add NEXUS target for RadioMaster Nexus (Original) flight controller
…peed-on-new-data

imu: compute GPS 3D speed only on new GPS data
…y-hot-path-opts

optimize imuMahonyAHRSupdate() hot path (5 micro-opts)
STM32F405RGT6-based flight controller by PauRC.

Hardware features:
- IMU: ICM42605/ICM42688P or BMI270 (board variant, same CS pin PC14)
- OSD: MAX7456 on SPI1
- Blackbox: 16MB SPI flash on SPI2
- Baro: SPL06/DPS310/BMP280/MS5611 (I2C1)
- 6x UART + 1x SoftSerial (PA2, shared with UART2 TX)
- 11x PWM outputs with DShot/DMAR support
- LED strip, PINIO (2 channels), airspeed ADC
- 30.5x30.5mm mounting pattern

Closes iNavFlight#11089
…icit_timers_first

use explicitly assigned motor and servo timers before auto timers
docs: add Backup and Restore documentation for Configurator auto-backup
Add MSP2 link stats message + fix missing msp-set-wp-index-and-altitu…
…ingrc-f4wing-ledstrip

target/FLYINGRCF4WINGMINI_NOT_RECOMMENDED: add LED strip support
Merge MSP2_INAV_SET_WP_INDEX (8737) and MSP2_INAV_SET_CRUISE_HEADING (8739)
from upstream with MSP2_INAV_SET_AUX_RC (8752), maintaining numeric order.
MSP2_INAV_SET_AUX_RC (0x2230) — Bandwidth-efficient auxiliary RC channel updates
Change gpsState.hwVersion from uint32_t to uint8_t and introduce a
structured bit-field encoding for the hardware version byte:
  bits [7:6] = series  (0b01 = u-blox Neo/M series)
  bits [5:0] = generation (e.g. 8=M8, 9=M9, 10=M10)

Update UBX_HW_VERSION_* constants accordingly (e.g. M8=0x48, M9=0x49,
M10=0x4A). Change MSP_GPSSTATISTICS to send hwVersion as a single byte
(sbufWriteU8) instead of four bytes (sbufWriteU32).

The bit-field layout reserves series values 0b10 and 0b11 for future
chip families (e.g. u-blox F9, other manufacturers).

Tested with M9 and M10 receivers — auto-detection working correctly.
…ion-uint8

GPS: fix hwVersion field size from uint32_t to uint8_t
- Accept maintenance-10.x structure for inav_enums.json and
  msp_messages.json (both gained version wrapper and build metadata)
- Accept maintenance-10.x removal of msp_messages.checksum and rev
  (versioning moved into msp_messages.json version field)
- Accept maintenance-10.x README/gen_docs.sh improvements, removing
  the checksum-based rev counter
- Keep both MSP handlers from each branch in fc_msp.c:
  MSP2_INAV_SET_AUX_RC (from 9.x) and MSP2_INAV_FLIGHT_AXIS_*
  (from 10.x, under USE_RX_MSP && USE_MSP_RC_OVERRIDE guard)
Forward-ported from maintenance-9.x along with its fc_msp.c handler.
Was missing from the initial merge conflict resolution.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 25, 2026

Test firmware build ready — commit 3355335

Download firmware for PR #11512

234 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

Accepted 10.x's inav_enums.json during conflict resolution, but the
merged source (which includes 9.x additions auto-merged from source
headers) has different enum values for 7 types. Patched to match
the actual merged source code:

- accelerationSensor_e: ACC_ICM45686 inserted (shifts ACC_FAKE 11→12)
- gyroSensor_e: GYRO_ICM45686 inserted (shifts GYRO_FAKE 11→12)
- devHardwareType_e: DEVHW_ICM45686 inserted (shifts all subsequent +1)
- ledModeIndex_e: LED_MODE_LOITER inserted (shifts LED_SPECIAL 6→7)
- crsfFrameType_e: AIRSPEED_SENSOR/RPM/TEMP frame types added
- crsfFrameTypeIndex_e: matching index entries added
- navigationFSMEvent_t: NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_JUMP added

10.x-only additions (geoAltitudeDatumFlag_e, logicOperation_e,
multi_function_e, resolutionType_e) are unchanged.
MSP2_INAV_GET_LINK_STATS (8451), MSP2_INAV_SET_WP_INDEX (8737), and
MSP2_INAV_SET_CRUISE_HEADING (8739) are all present in the merged
fc_msp.c and msp_protocol_v2_inav.h but were absent from the
documentation after accepting 10.x's msp_messages.json.
@sensei-hacker sensei-hacker merged commit edb1657 into iNavFlight:maintenance-10.x Apr 25, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants