-
Notifications
You must be signed in to change notification settings - Fork 1.8k
.pr_agent_auto_best_practices
Pattern 1: Validate external inputs (env vars, CLI args, and incoming protocol payload sizes) before use, and fail deterministically with a clear error when inputs are missing or malformed.
Example code before:
// env var / CLI arg used without validation
int pr = parseInt(getenv("PR_NUMBER")); // could be NaN/NULL
const char *path = argv[1]; // argc not checked
// protocol handler reads without checking length
uint8_t item = buf[0];
uint16_t pos = read_u16(buf + 1);
Example code after:
// validate env var / CLI args
const char *s = getenv("PR_NUMBER");
if (!s) { fprintf(stderr, "PR_NUMBER missing\n"); return 1; }
char *end = NULL;
long pr = strtol(s, &end, 10);
if (*s == '\0' || *end != '\0') { fprintf(stderr, "PR_NUMBER invalid\n"); return 1; }
if (argc < 2) { fprintf(stderr, "usage: tool <path>\n"); return 2; }
// validate payload size before reading
if (dataSize < 3) return MSP_RESULT_ERROR;
uint8_t item = buf[0];
uint16_t pos = read_u16(buf + 1);
Relevant past accepted suggestions:
Suggestion 1:
[reliability] `parseInt` result not validated
`parseInt` result not validated
The PR comment step uses `parseInt(process.env.PR_NUMBER)` without checking for `NaN` or enforcing base-10 parsing, which can lead to non-deterministic behavior if the env var is missing/malformed. This violates the requirement to validate external inputs and handle invalid values deterministically.The workflow parses PR_NUMBER from an environment variable using parseInt(...) and then uses it without checking for NaN (and without specifying radix 10). If the env var is missing or malformed, this can produce non-deterministic behavior (e.g., NaN in URLs / API params) instead of a clear, deterministic failure.
This job runs with elevated permissions (pull-requests: write) and should validate external inputs (including env vars derived from artifacts/outputs) before use.
- .github/workflows/pr-test-builds.yml[107-110] բավ
Suggestion 2:
Add payload size validation check
Add a payload size check in the MSP_OSD_CUSTOM_POSITION handler to ensure the incoming data is at least 3 bytes before reading from the buffer.
src/main/fc/fc_msp.c [2718-2731]
case MSP_OSD_CUSTOM_POSITION: {
+ if (dataSize < 3) {
+ return MSP_RESULT_ERROR;
+ }
uint8_t item;
sbufReadU8Safe(&item, src);
if (item < OSD_ITEM_COUNT){ // item == addr
osdEraseCustomItem(item);
osdLayoutsConfigMutable()->item_pos[0][item] = sbufReadU16(src) | (1 << 13);
osdDrawCustomItem(item);
}
else{
return MSP_RESULT_ERROR;
}
break;
}Suggestion 3:
Suggestion 4:
Pattern 2: Avoid build fragility by explicitly including required headers/macros and by removing/ignoring generated build outputs that contain machine-specific paths or state.
Example code before:
// header relies on transitive includes for macros/types
#pragma once
#define MY_ID CONCAT4(A, B, C, D) // CONCAT4 not defined here
// generated build files accidentally committed
set(CMAKE_ASM_TARGET_INCLUDE_PATH "/Users/alice/project/include")
Example code after:
// header includes what it uses
#pragma once
#include "common/utils.h" // defines CONCAT4
#define MY_ID CONCAT4(A, B, C, D)
// generated build outputs removed and ignored
# .gitignore
CMakeFiles/
CMakeCache.txt
Relevant past accepted suggestions:
Suggestion 1:
[reliability] Headers rely on transitive CONCAT4
Headers rely on transitive CONCAT4
The new bus_spi_stm32{h7,f7}xx.h headers use CONCAT4 but do not include the header that defines it, relying on current include order/transitive includes from other headers. This is a latent build fragility: a future refactor or reuse of these headers elsewhere can cause compile failures (e.g., CONCAT4 undefined).The new SPI AF lookup table headers use CONCAT4(...) but do not include the header that defines it (common/utils.h). They currently compile only due to transitive includes (via drivers/io.h → io_def.h → common/utils.h) and therefore are fragile to include-order changes or reuse.
This is a latent build fragility / maintainability issue: it may not break today, but it can break later during refactors or if another file includes these headers without including common/utils.h first.
- src/main/drivers/bus_spi_stm32h7xx.h[32-38]
- src/main/drivers/bus_spi_stm32f7xx.h[36-42]
Suggestion 2:
Remove generated build file from repository
Remove the generated CMake build file from the repository. It contains user-specific absolute paths that will cause build failures for other developers and should be added to .gitignore.
-# Consider dependencies only in project.
-set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF)
+# This file should be removed from the repository.
-# The set of languages for which implicit dependencies are needed:
-set(CMAKE_DEPENDS_LANGUAGES
- "ASM"
- )
-# The set of files for implicit dependencies of each language:
-set(CMAKE_DEPENDS_CHECK_ASM
- "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/lib/main/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal2.S" "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/src/src/main/target/AXISFLYINGF7PRO/CMakeFiles/AXISFLYINGF7PRO_for_bl.elf.dir/__/__/__/__/lib/main/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal2.S.obj"
- "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/src/main/startup/startup_stm32f722xx.s" "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/src/src/main/target/AXISFLYINGF7PRO/CMakeFiles/AXISFLYINGF7PRO_for_bl.elf.dir/__/__/startup/startup_stm32f722xx.s.obj"
- )
-set(CMAKE_ASM_COMPILER_ID "GNU")
-
-# Preprocessor definitions for this target.
-set(CMAKE_TARGET_DEFINITIONS_ASM
-...
-
-# The include file search paths:
-set(CMAKE_ASM_TARGET_INCLUDE_PATH
- "main/target/AXISFLYINGF7PRO"
- "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/lib/main/STM32F7/Drivers/STM32F7xx_HAL_Driver/Inc"
- "/Users/ahmed/Desktop/Projects/INAV-RPiOSD/inav/lib/main/STM32F7/Drivers/CMSIS/Device/ST/STM32F7xx/Include"
-...
-Suggestion 3:
Remove generated file from version control
Remove the generated Makefile.cmake file from version control. This file is environment-specific and should be ignored by adding the CMakeFiles directory to .gitignore.
src/CMakeFiles/Makefile.cmake [1-9]
-# CMAKE generated file: DO NOT EDIT!
-# Generated by "Unix Makefiles" Generator, CMake Version 4.1
+# This file should be removed from the pull request and repository.
-# The generator used is:
-set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles")
-
-# The top level Makefile was generated from the following files:
-set(CMAKE_MAKEFILE_DEPENDS
- "CMakeCache.txt"
-...
-Pattern 3: Add explicit timeout handling for polling/wait loops and DMA/IO state transitions; if a timeout is hit, return a specific error instead of breaking/continuing with partial state.
Example code before:
while (!(REG & READY_BIT)) {
if (--timeout == 0) break; // continues afterward with incomplete state
}
disable_dma_stream();
// assume DMA is disabled; proceed to reconfigure
configure_dma_stream();
Example code after:
while (!(REG & READY_BIT)) {
if (--timeout == 0) return ERR_TIMEOUT;
}
uint32_t t = DMA_DISABLE_TIMEOUT;
disable_dma_stream();
while (dma_stream_enabled() && --t) { /* wait */ }
if (t == 0) return ERR_DMA_STILL_ACTIVE;
configure_dma_stream();
Relevant past accepted suggestions:
Suggestion 1:
Suggestion 2:
New proposed code:
Suggestion 3:
Pattern 4: Guard numeric edge cases in calculations (e.g., division by zero and vector normalization of near-zero magnitude), and use consistent sentinel values for invalid/no-data states.
Example code before:
float tpa = (airspeed - ref) / ref; // ref could be 0
normalize(v); // v could be ~0 length
// failed read only partially resets data
mag.x = 0; mag.z = 0; // mag.y left stale
measurement_cm = 0; // looks like valid "0cm"
Example code after:
float tpa = 0.0f;
if (ref > 0.0f) tpa = (airspeed - ref) / ref;
if (norm2(v) > 0.01f) normalize(v);
// reset all axes consistently on failure
mag.x = mag.y = mag.z = 0;
// sentinel for "no new data"
measurement_cm = RANGEFINDER_NO_NEW_DATA;
Relevant past accepted suggestions:
Suggestion 1:
Prevent division by zero during normalization
Add a check to ensure vCoGlocal has a non-zero magnitude before normalization to prevent a potential division-by-zero error.
src/main/flight/imu.c [472-482]
-if (vectorNormSquared(&vHeadingEF) > 0.01f) {
+if (vectorNormSquared(&vHeadingEF) > 0.01f && vectorNormSquared(&vCoGlocal) > 0.01f) {
// Normalize to unit vector
vectorNormalize(&vHeadingEF, &vHeadingEF);
vectorNormalize(&vCoGlocal, &vCoGlocal);
// error is cross product between reference heading and estimated heading (calculated in EF)
vectorCrossProduct(&vCoGErr, &vCoGlocal, &vHeadingEF);
// Rotate error back into body frame
quaternionRotateVector(&vCoGErr, &vCoGErr, &orientation);
}Suggestion 2:
Prevent division-by-zero in TPA calculation
Add a check to prevent division-by-zero when referenceAirspeed is zero in the tpaThrottle calculation, falling back to the standard throttle value if necessary.
src/main/flight/pid.c [501-502]
const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
-tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
+if (referenceAirspeed > 0) {
+ tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
+} else {
+ // Fallback to regular throttle if reference airspeed is not configured
+ tpaThrottle = rcCommand[THROTTLE];
+}Suggestion 3:
Suggestion 4:
Reset all magnetometer axes
The Y-axis is not being reset to zero in case of failed read, which could leave stale data. All three axes should be reset to maintain consistency and prevent potential issues with outdated magnetometer readings.
src/main/drivers/compass/compass_qmc5883p.c [131-133]
// set magData to zero for case of failed read
mag->magADCRaw[X] = 0;
+mag->magADCRaw[Y] = 0;
mag->magADCRaw[Z] = 0;Pattern 5: Keep behavior and semantics consistent across modules and documentation by aligning shared logic, operand conventions, and API signatures (and updating docs/examples when code behavior changes).
Example code before:
// module A priority
if (FAILSAFE) mode="FS";
else if (MANUAL) mode="MANU";
else if (GEOZONE) mode="GEO";
// module B priority differs
if (FAILSAFE) mode="FS";
else if (GEOZONE) mode="GEO";
else if (MANUAL) mode="MANU";
// docs/example call doesn't match function signature
createLogicCondition(id, op1, op2, rawValue, flags);
Example code after:
// shared/consistent priority order (or centralized helper)
const char *mode = getFlightModeLabel(); // same logic used by both modules
// docs/examples match actual API contract
createLogicCondition(id,
(operand_t){ .type=OP_FLIGHT, .field=FIELD_WIND_DIR },
(operand_t){ .type=OP_CONST, .value=123 },
flags);
Relevant past accepted suggestions:
Suggestion 1:
Harmonize operand semantics and docs
Mirror the sign and invalid-return conventions with the new relative wind field in docs and keep operand meanings consistent; update docs and ensure both operands follow the same invalid sentinel and frame definitions.
src/main/programming/logic_condition.c [763-785]
-case LOGIC_CONDITION_OPERAND_FLIGHT_WIND_DIRECTION: // deg
+case LOGIC_CONDITION_OPERAND_FLIGHT_WIND_DIRECTION: // deg, 0..359, -1 invalid
#ifdef USE_WIND_ESTIMATOR
{
if (isEstimatedWindSpeedValid()) {
- uint16_t windAngle;
- getEstimatedHorizontalWindSpeed(&windAngle);
- int32_t windHeading = windAngle + 18000; // Correct heading to display correctly.
-
- windHeading = (CENTIDEGREES_TO_DEGREES((int)windHeading));
- while (windHeading < 0) {
- windHeading += 360;
- }
- while (windHeading >= 360) {
- windHeading -= 360;
- }
- return windHeading;
- } else
+ uint16_t windAngleCd;
+ getEstimatedHorizontalWindSpeed(&windAngleCd);
+ // Convert wind vector angle (towards) to heading-from (meteorological) in degrees [0,360)
+ int32_t headingDeg = CENTIDEGREES_TO_DEGREES((int)(windAngleCd + 18000));
+ while (headingDeg < 0) headingDeg += 360;
+ while (headingDeg >= 360) headingDeg -= 360;
+ return headingDeg;
+ } else {
return -1;
+ }
}
#else
- return -1;
+ return -1;
#endif
- break;
+ break;Suggestion 2:
Align flight mode priority logic
Align the flight mode priority logic in crsf.c with osd.c. The current implementation has a different priority for MANUAL_MODE and GEOZONE between the two files, which should be synchronized.
src/main/telemetry/crsf.c [356-368]
#ifdef USE_FW_AUTOLAND
if (FLIGHT_MODE(NAV_FW_AUTOLAND)) {
flightMode = "LAND";
} else
#endif
if (FLIGHT_MODE(FAILSAFE_MODE)) {
flightMode = "!FS!";
+ } else if (FLIGHT_MODE(MANUAL_MODE)) {
+ flightMode = "MANU";
#ifdef USE_GEOZONE
} else if (FLIGHT_MODE(NAV_SEND_TO) && !FLIGHT_MODE(NAV_WP_MODE)) {
flightMode = "GEO";
-#endif
- } else if (FLIGHT_MODE(MANUAL_MODE)) {
- flightMode = "MANU";
+#endifSuggestion 3:
Suggestion 4:
[Auto-generated best practices - 2026-04-01]
INAV Version Release Notes
9.0.0 Release Notes
8.0.0 Release Notes
7.1.0 Release Notes
7.0.0 Release Notes
6.0.0 Release Notes
5.1 Release notes
5.0.0 Release Notes
4.1.0 Release Notes
4.0.0 Release Notes
3.0.0 Release Notes
2.6.0 Release Notes
2.5.1 Release notes
2.5.0 Release Notes
2.4.0 Release Notes
2.3.0 Release Notes
2.2.1 Release Notes
2.2.0 Release Notes
2.1.0 Release Notes
2.0.0 Release Notes
1.9.1 Release notes
1.9.0 Release notes
1.8.0 Release notes
1.7.3 Release notes
Older Release Notes
QUICK START GUIDES
Getting started with iNav
Fixed Wing Guide
Howto: CC3D flight controller, minimOSD , telemetry and GPS for fixed wing
Howto: CC3D flight controller, minimOSD, GPS and LTM telemetry for fixed wing
INAV for BetaFlight users
launch mode
Multirotor guide
YouTube video guides
DevDocs Getting Started.md
DevDocs INAV_Fixed_Wing_Setup_Guide.pdf
DevDocs Safety.md
Connecting to INAV
Bluetooth setup to configure your flight controller
DevDocs Wireless Connections (BLE, TCP and UDP).md\
Flashing and Upgrading
Boards, Targets and PWM allocations
Upgrading from an older version of INAV to the current version
DevDocs Installation.md
DevDocs USB Flashing.md
Setup Tab
Live 3D Graphic & Pre-Arming Checks
Calibration Tab
Accelerometer, Compass, & Optic Flow Calibration
Alignment Tool Tab
Adjust mount angle of FC & Compass
Ports Tab
Map Devices to UART Serial Ports
Receiver Tab
Set protocol and channel mapping
Mixer Tab
Set aircraft type and how its controlled
Outputs Tab
Set ESC Protocol and Servo Parameters
Modes Tab
Assign flight modes to transmitter switches
Standard Modes
Navigation Modes
Return to Home
Fixed Wing Autolaunch
Auto Launch
Configuration Tab
No wiki page currently
Failsafe Tab
Set expected behavior of aircraft upon failsafe
PID Tuning
Navigation PID tuning (FW)
Navigation PID tuning (MC)
EZ-Tune
PID Attenuation and scaling
Tune INAV PID-FF controller for fixedwing
DevDocs Autotune - fixedwing.md
DevDocs INAV PID Controller.md
DevDocs INAV_Wing_Tuning_Masterclass.pdf
DevDocs PID tuning.md
DevDocs Profiles.md
Rangefinder & Optic Flow
Optic Flow and Rangefinder Setup
Setup and usage for terrain following & GPS-free position hold
OSD and VTx
DevDocs Betaflight 4.3 compatible OSD.md
OSD custom messages
OSD Hud and ESP32 radars
DevDocs OSD.md
DevDocs VTx.md
LED Strip
DevDocs LedStrip.md
Programming
DevDocs Programming Framework.md
Adjustments
DevDocs Inflight Adjustments.md
Mission Control
iNavFlight Missions
DevDocs Safehomes.md
MultiWii Serial Protocol
MSP V2
MSP Messages reference guide
MSP Navigation Messages
INAV MSP frames changelog
Telemetry
INAV Remote Management, Control and Telemetry
MAVlink Control and Telemetry
Lightweight Telemetry (LTM)
Tethered Logging
Log when FC is connected via USB
Blackbox
DevDocs Blackbox.md
INAV blackbox variables
DevDocs USB_Mass_Storage_(MSC)_mode.md
CLI
iNav CLI variables
DevDocs Cli.md
DevDocs Settings.md
VTOL
DevDocs MixerProfile.md
DevDocs VTOL.md
TROUBLESHOOTING
"Something" is disabled Reasons
Blinkenlights
Sensor auto detect and hardware failure detection
Pixel OSD FAQs
TROUBLESHOOTING
Why do I have limited servo throw in my airplane
ADTL TOPICS, FEATURES, DEV INFO
AAT Automatic Antenna Tracker
Building custom firmware
Default values for different type of aircrafts
Source Enums
Features safe to add and remove to fit your needs.
Developer info
Making a new Virtualbox to make your own INAV[OrangeRX LRS RX and OMNIBUS F4](OrangeRX-LRS-RX-and-OMNIBUS-F4)
Rate Dynamics
Target and Sensor support
Ublox 3.01 firmware and Galileo
DevDocs Controls
DevDocs 1wire.md
DevDocs ADSB.md
DevDocs Battery.md
DevDocs Buzzer.md
DevDocs Channel forwarding.md
DevDocs Display.md
DevDocs Fixed Wing Landing.md
DevDocs GPS_fix_estimation.md
DevDocs LED pin PWM.md
DevDocs Lights.md
DevDocs OSD Joystick.md
DevDocs Servo Gimbal.md
DevDocs Temperature sensors.md
OLD LEGACY INFO
Supported boards
DevDocs Boards.md
Legacy Mixers
Legacy target ChebuzzF3
Legacy target Colibri RACE
Legacy target Motolab
Legacy target Omnibus F3
Legacy target Paris Air Hero 32
Legacy target Paris Air Hero 32 F3
Legacy target Sparky
Legacy target SPRacingF3
Legacy target SPRacingF3EVO
Legacy target SPRacingF3EVO_1SS
DevDocs Configuration.md
Request form new PRESET
DevDocs Introduction.md
Welcome to INAV, useful links and products
UAV Interconnect Bus
DevDocs Rangefinder.md
DevDocs Rssi.md
DevDocs Runcam device.md
DevDocs Serial.md
DevDocs Telemetry.md
DevDocs Rx.md
DevDocs Spektrum bind.md
DevDocs INAV_Autolaunch.pdf