Skip to content

PINIO: fix operand order, add pwmOnPin() to JS transpiler, unify pinioSet#2587

Closed
sensei-hacker wants to merge 75 commits intoiNavFlight:maintenance-10.xfrom
sensei-hacker:feature/unified-pinio-pwm-output
Closed

PINIO: fix operand order, add pwmOnPin() to JS transpiler, unify pinioSet#2587
sensei-hacker wants to merge 75 commits intoiNavFlight:maintenance-10.xfrom
sensei-hacker:feature/unified-pinio-pwm-output

Conversation

@sensei-hacker
Copy link
Member

Summary

  • Fix PINIO_PWM operand order for backward compatibility: operandA=duty, operandB=pin (0=LED pin, 1=USER1, 2=USER2, ...). Old LED_PIN_PWM configs with operandA as duty and operandB=0 continue to work unchanged.
  • Rename condition label from "PINIO PWM" to "PWM on pin" to reflect the operand order in the UI.
  • Add inav.override.pwmOnPin(duty, pin) to the JavaScript transpiler with full compile (JS→LC) and decompile (LC→JS) support. Function name mirrors the label: duty first, then pin.
  • Fix transformBodyStatement to dispatch CallExpression nodes — previously, function calls inside if bodies were silently dropped.

Changes

  • js/logicConditionOperators.js — rename condition 52 label to "PWM on pin"
  • js/transpiler/transpiler/parser.js — recognize inav.override.pwmOnPin(duty, pin); fix CallExpression dispatch in transformBodyStatement
  • js/transpiler/transpiler/codegen.js — handle PinioPwm AST node → emit PINIO_PWM LC with operandA=duty, operandB=pin
  • js/transpiler/transpiler/action_decompiler.js — decompile to inav.override.pwmOnPin(duty, pin)
  • js/transpiler/transpiler/tests/pinio_pwm.test.cjs — round-trip tests (compile, decompile, JS→LC→JS) for LED pin, USER1, USER2
  • js/transpiler/transpiler/tests/run_pinio_pwm_tests.cjs — test runner

Testing

  • All 29 transpiler test suites pass (run_all_tests.cjs)
  • 7/7 new pinioPwm round-trip tests pass covering compile, decompile, and full round-trip for LED pin (pin=0), USER1 (pin=1), and USER2 (pin=2)
  • Backward compatibility verified: old LED_PIN_PWM configs with operandA=duty, operandB=0 correctly target the LED pin

Code Review

Reviewed for correctness of operand mapping, transpiler round-trip consistency, and backward compatibility.

Implement persistent last save directory feature that remembers the directory
used in file save dialogs and defaults to it in future save operations.

Changes:
- Modified dialog.js showSaveDialog wrapper to store and retrieve last directory
- Uses electron-store via electronAPI.storeGet/storeSet
- Automatically extracts directory from selected file path
- Sets as defaultPath for subsequent saves if no path specified
- Cross-platform path handling (supports both / and \ separators)

Benefits:
- Reduces user friction when saving multiple files
- Persists across app restarts
- Works for all save operations (blackbox logs, diffs, configs, etc.)
- No UI changes required - transparent to user
- Backwards compatible - gracefully handles no saved directory

Closes part of UX improvements for file management.
Move save directory logic to main process IPC handler where it belongs.
The implementation now:
- Stores the last used directory in electron-store
- Combines saved directory with provided filename using path.join()
- Handles edge cases: filename-only, full paths, no saved directory
- Preserves directory on cancel (only saves on successful file selection)

This fixes the issue where the implementation in renderer process was never called.
The firmware flasher was unable to match boards with multiple underscores
in their names (like TBS_LUCID_H7_WING) because the old code only replaced
the first underscore with a space, creating a mismatch between dictionary
keys and lookup values.

Changes:
- Add normalizeTargetName() function to convert hyphens to underscores
- Fix parseFilename() to replace ALL underscores/hyphens with spaces for display
- Key releases dictionary by normalized raw_target instead of modified target
- Normalize all lookups to use consistent underscore format
- Support both underscore and hyphen filename variants

This fixes board selection for targets like TBS_LUCID_H7_WING and enables
support for hyphen-based filenames as a workaround (TBS-LUCID-H7-WING).
Eliminates 6 of 7 normalizeTargetName() calls by normalizing target names
once at the data source (parseFilename/parseDevFilename functions) instead
of repeatedly at consumption points.

Changes:
- Rename raw_target to target_id for semantic clarity
- Add normalization in parseDevFilename() and parseFilename()
- Remove redundant normalizeTargetName() calls throughout (6 eliminated)
- Keep one necessary call for FC.CONFIG.target (external data source)

Benefits:
- Single normalization per filename parse (better performance)
- Impossible to forget normalization (always available in result.target_id)
- Clearer code intent and improved maintainability
- Net reduction of 4 lines (17 insertions, 21 deletions)
- Simplify normalizeTargetName() comment to "Allow hyphens due to 9.0.0 patch"
- Remove "Normalized: ..." comments since function name is self-explanatory
- Keep "Display: ..." comments for clarity on user-facing strings
Implement user-friendly GPS configuration presets for M8/M9/M10 modules:

- Add GPS preset dropdown with Auto-detect, Manual, M8, M9, M10, and M10-highperf options
- Add GPS update rate input field (previously not exposed in UI)
- Extend MSP_GPSSTATISTICS to parse hwVersion for auto-detection
- Preset configuration disables (but shows) settings when active
- Add preset info box explaining each preset's characteristics

Presets configured per manager feedback:
- M8: 4 constellations @ 8Hz (conservative)
- M9: 4 constellations @ 10Hz (hardware limit: 16 sats)
- M10: 4 constellations @ 6Hz (default CPU clock safe rate)
- M10-highperf: 4 constellations @ 10Hz (for high-perf clock users)
- Manual: Full user control (default for existing users)

Auto-detection uses FC.GPS_DATA.hwVersion from MSP_GPSSTATISTICS
(firmware extension pending - see documentation).

Translation strings added for en locale.

Related: GPS optimization research based on Jetrell's M10 testing data
…ection

- Add GPS_PRESETS object with 7 preset options
- Split M9 into Precision (5Hz, 32 sats) and Sport (10Hz, 16 sats) modes
- Update M10 presets (3 const @ 8Hz, 4 const @ 10Hz for high-perf)
- Add detectGPSPreset() to map hwVersion to preset
- Add applyGPSPreset() to apply constellation/rate settings
- Extend MSPHelper to parse hwVersion from MSP_GPSSTATISTICS (backward compatible)
- Update HTML dropdown with new preset options

Research: M9 hardware limits to 16 satellites at >=10Hz, 32 satellites at <10Hz
See: claude/developer/docs/gps/m9-16-satellite-limitation-official.md
When navigating away from GPS tab and back, the preset dropdown
was resetting to "Manual Settings" every time, even if the GPS
module had been auto-detected.

Changes:
- Check if GPS data (hwVersion) is already available on tab init
- If available and valid (>0), auto-detect and apply preset
- If not available, fall back to manual mode as before

This preserves the auto-detected preset when switching between tabs,
providing a smoother user experience.

Related: GPS preset UI feature
Addresses Qodo code review suggestion to ensure state consistency
when programmatically setting GPS configuration values.

When presets change constellation checkboxes and rate values, we now
trigger their 'change' events. This follows the pattern used in other
tabs (firmware_flasher.js, pid_tuning.js, sensors.js) and ensures:
- Save button state updates correctly
- Any change event handlers fire properly
- Configuration tracking remains consistent

Without .trigger('change'), programmatic updates bypass event handlers
that may be listening for user changes to these controls.
Problem:
The decompiler was eagerly decompiling both operandA and operandB for all action operations,
even when operandB was unused. This caused incorrect type-specific validation warnings for
operations like SET_PROFILE (operation 42) which only uses operandA.

Example: SET_PROFILE with operandB type=6 (PID), value=1700 (garbage data) would trigger:
"Invalid PID operand value 1700. Valid range is 0-3."

Solution:
Added operation-specific operand handling with two categories:
- operandAOnlyOperations: Operations that only use operandA (skip operandB decompilation)
- noOperandOperations: Operations that use no operands (skip both)

Additionally, added version detection warnings for unexpected operands:
- Warns when unused operands have non-zero type or value
- Helps detect firmware/configurator version mismatches
- Shows operation name, type, and value for debugging

Example warning: "Unexpected operand B to Set Profile operation (type=6, value=1700).
This may indicate a firmware version mismatch."

Benefits:
- Prevents type-specific validation errors on garbage data in unused operands
- Preserves validation for operations that legitimately use PID/other operands
- Provides version detection when firmware adds new operand usage
Organizes the 24 configuration tabs into 8 collapsible accordion groups
for improved navigation and reduced visual clutter.

Groups:
- Setup & Configuration (5 tabs)
- Flight Control (5 tabs)
- Tuning (3 tabs)
- Navigation & Mission (2 tabs)
- Sensors & Peripherals (3 tabs)
- Data Logging (2 tabs)
- Programming (2 tabs)
- Tools (2 tabs)

Implementation:
- Added accordion group structure to index.html
- Added accordion styling to main.css (preserves INAV cyan theme)
- Added expand/collapse JavaScript to configurator_main.js
- Added English translation keys for navigation groups
- First group (Setup & Configuration) expands by default

No new dependencies required - uses existing jQuery and CSS transitions.
Adds an icon-only toggle button at the bottom of the navigation menu to
expand or collapse all accordion groups.

Features:
- SVG icon button that swaps between expand (double chevron down) and
  collapse (double chevron up) states
- Clicking expands all 8 navigation groups or collapses to first group only
- Preference persists across configurator restarts via electron-store
- When all groups expanded, headers become minimal cyan divider lines to
  maximize vertical space
- Icon-only design saves space - all 24 tabs fit without scrolling
- Smooth CSS transitions for icon swap and header state changes

Implementation:
- Toggle button in index.html with both expand/collapse SVG icons
- JavaScript in configurator_main.js handles toggle logic and persistence
- CSS in main.css for compact headers when expanded and icon styling
- Translation keys in locale/en/messages.json for accessibility

Addresses need for quick access to all tabs while maintaining visual
organization of accordion groups.
Adds WCAG-compliant accessibility features to accordion navigation:

HTML changes:
- Added role="button" to all group headers for screen reader compatibility
- Added tabindex="0" to make headers keyboard-navigable
- Added aria-expanded="false" initial state to indicate collapsed groups

JavaScript changes:
- Updates aria-expanded dynamically when groups expand/collapse
- Added keyboard event handler for Enter and Space keys
- Ensures aria-expanded is set correctly on initialization
- Updates aria-expanded when using expand/collapse all button
- Fixed localization attribute on JavaScript Programming tab (i18n → data-i18n)

Benefits:
- Screen readers announce group headers as interactive buttons
- Keyboard users can Tab to headers and activate with Enter/Space
- Assistive technology correctly reports expanded/collapsed state
- Meets WCAG 2.1 Level AA compliance for keyboard navigation

Addresses qodo-merge code review suggestions for accessibility.
Augment decompiler to track which Logic Conditions map to which lines
in generated JavaScript code. This enables real-time highlighting of
active conditions in the JavaScript Programming tab.

Key features:
- 3-pass mapping algorithm handles simple, compound, and nested conditions
- Compound conditions (a && b) correctly map all sub-LCs to same line
- Activator chains propagate line numbers to child LCs
- Hoisted variables and sticky/timer patterns tracked
- Returns lcToLineMapping in decompile() result

Part of Feature 1: Active LC Highlighting (Phase 1/5)
Implement real-time status polling and gutter decoration updates in the
JavaScript Programming tab to show which Logic Conditions are currently
active/true.

Key features:
- Status polling every 100ms using MSPChainer
- updateActiveHighlighting() filters true LCs and applies gutter markers
- clearActiveHighlighting() when code is dirty (unsaved changes)
- Proper cleanup on tab switch/disconnect
- isDirty check prevents highlighting stale code

Part of Feature 1: Active LC Highlighting (Phase 2/5)
Implement CSS and Monaco editor configuration for green checkmark gutter
markers that indicate active/true Logic Conditions.

Key changes:
- Add .lc-active-true CSS class with SVG green checkmark icon
- Add Monaco gutter margin background styling
- Enable glyphMargin: true in Monaco editor options
- Set up proper cursor and sizing for gutter decorations

Part of Feature 1: Active LC Highlighting (Phase 3/5)
Fix 'Cannot read properties of null' error in updateActiveHighlighting()
by adding proper null checks for FC.LOGIC_CONDITIONS_STATUS and
FC.LOGIC_CONDITIONS before accessing .get().

This prevents errors during tab initialization when FC data is still loading.
The onChange handler was firing after setValue() during load, causing
isDirty to be set to true even after we cleared it. This prevented the
highlighting from ever appearing because updateActiveHighlighting()
returns early when isDirty is true.

Fixed by using setTimeout() to clear isDirty after the setValue() change
event has been processed.
Previous approach tried to find LCs by parsing the generated code for
/* LC X */ comments, but normal if-statements don't have these comments.

New approach:
- Track LC index and line content during code generation
- After adding boilerplate, search for the tracked lines in final code
- Map LC index to actual line numbers in final output

This ensures all if-statements and their associated LCs get mapped
correctly for the active highlighting feature.
Track what's being searched for and what's being found to diagnose
why the LC-to-line mapping is empty.
This will help us diagnose why the green checkmarks aren't appearing
by logging:
- When the function is called
- If isDirty is blocking it
- What the LC-to-line mapping is
- If FC data is available
- Which LCs are TRUE
- What lines should be highlighted
- If decorations are created
FC.LOGIC_CONDITIONS_STATUS.get() requires a condition index parameter
and returns a single value. We need getAll() to get the entire status array.

This was causing 'FC data is null' errors and preventing any highlighting
from appearing.
This completes the active LC highlighting feature with two major improvements:

1. FALSE condition indicators: Gray hollow circles (○) display when conditions
   evaluate to FALSE, complementing the existing green checkmarks for TRUE
   conditions. Mixed states (TRUE and FALSE on same line) show green checkmark.

2. Transpiler-side line tracking: LC-to-line mappings are now generated during
   transpilation, providing immediate visual feedback after "Transpile" or
   "Save to FC" without requiring "Load from FC" roundtrip. Correctly adjusts
   for auto-added import statement offset.

Technical changes:
- Add lineOffset tracking in codegen to account for prepended import lines
- Store currentSourceLine context during statement generation
- Return lcToLineMapping in transpiler result
- Update tab to use transpiler mapping immediately after transpile/save
- Change polling interval from 100ms to 500ms to reduce MSP load (2Hz vs 10Hz)
- Reorder checks: verify FC data availability before isDirty state
- Clean up excessive debug logging for production readiness

Testing:
- Verified circles appear on correct lines after transpile
- Tested TRUE/FALSE/MIXED states display properly
- Confirmed decompiler mapping replaces transpiler mapping on load
- Reviewed with inav-code-review agent - all critical issues resolved
Fixes all 6 medium-priority issues identified by qodo-merge bot:
1. Clear stale decorations when loading code from FC
2. Clear mapping/decorations when loading default code
3. Add in-flight guard to prevent overlapping MSP polling requests
4. Remove duplicate intervals before adding new one
5. Improve type safety with Array.isArray() checks for MSP data

Code organization improvements:
- Extract highlighting logic to new module js/transpiler/lc_highlighting.js
- Reduce tab file from 928 to 893 lines (-35 lines)
- Create 5 testable, pure functions: categorizeLCsByStatus(),
  mapLCsToLines(), createMonacoDecorations(), applyDecorations(),
  clearDecorations()
- Better separation of concerns (tab orchestrates, module implements)
- Improved code maintainability and testability
Implement visual indicator showing when JavaScript editor content matches
flight controller storage vs when changes exist locally.

Key features:
- Save button disabled when isDirty=false (code matches FC)
- Save button enabled when isDirty=true (unsaved changes)
- updateSaveButtonState() called at all isDirty change points
- Uses existing .disabled CSS styling for visual feedback

Part of Feature 2: Code Sync Status
…ing tab

Feature 2 - Code Sync Status:
- Disable Save button when editor matches FC (isDirty = false)
- Enable Save button when code is modified (isDirty = true)
- Uses existing .disabled CSS class with pointer-events: none

Feature 3 - Gvar Display:
- Display live non-zero global variable values as inline hints
- Format: // gvar[index] = value
- Position at end of line where gvar is referenced
- Deduplicate - show each gvar only once at first occurrence
- Auto-update at 500ms intervals via MSP polling
- Implemented using Monaco Content Widgets API

Implementation details:
- Created js/transpiler/gvar_display.js module for gvar functionality
- Added updateSaveButtonState() to manage Save button state
- Added updateGvarDisplay() for real-time gvar value display
- Integrated with existing MSPChainer for efficient polling
- CSS styling: opacity 0.65, italic, subtle gray color
After code review, added critical error handling to prevent silent failures:
- Monaco widget operations now wrapped in try-catch blocks
- MSP chainer exit point updates protected with error handling
- Fixed cleanup bug (gvarDecorations -> gvarWidgets)
- Added console logging for debugging widget failures

These changes ensure the gvar display feature degrades gracefully
instead of breaking the polling loop if Monaco operations fail.
sensei-hacker and others added 26 commits February 8, 2026 13:14
…NavFlight#2536)

* Fix JS Programming decompiler: render childless boolean conditions

The decompiler was skipping boolean conditions with no children,
assuming they were all "helper conditions" used as operands elsewhere.

However, some childless conditions (like flight parameter checks with
activators) need to be rendered for external reference (e.g., Global
Functions, OSD).

Changed decompileTree() to only skip childless conditions that cannot
be externally referenced. Conditions that could be referenced externally
are now rendered as empty if blocks with a comment.

Fixes: Logic condition 23 (airspeed < 1111 with activator) was
completely missing from decompiled output.

Added comprehensive regression test suite with 7 test cases covering
childless boolean conditions, activators, and external reference scenarios.

All existing tests pass (27/27 test suites).

* Fix decompiler GVAR hoisting bug

The decompiler was hoisting expressions that read from GVARs to the top
of the decompiled code (as const declarations), causing them to use OLD
GVAR values instead of NEW values set by earlier logic conditions.

Root Cause:
ActivatorHoistingManager.identifyHoistedVars() didn't check if an LC
reads from GVARs before hoisting to global scope. GVAR values are dynamic
and can be set at runtime, so hoisting breaks execution order.

Fix:
- Added readsFromGvar() method to detect GVAR reads (recursively checking
  LC operands for transitive dependencies)
- Skip hoisting for any LC that reads from GVARs
- Expressions using GVARs now render inline, preserving execution order

Example (BEFORE - broken):
  const cond1 = (gvar[7] * 1000 / 45) - 500;  // Uses OLD value
  if (rc[8].low) { gvar[7] = 0; }  // Sets NEW value
  gvar[6] = cond1;  // Wrong\!

Example (AFTER - correct):
  if (rc[8].low) { gvar[7] = 0; }  // Sets value first
  gvar[6] = (gvar[7] * 1000 / 45) - 500;  // Uses NEW value

Testing:
- Added comprehensive regression test suite (3 test cases)
- Tests verify GVAR assignments occur before GVAR usage
- All existing tests pass (27/28 suites)

Files modified:
- js/transpiler/transpiler/activator_hoisting.js
- js/transpiler/transpiler/tests/gvar_hoisting_order.test.cjs (new)
- js/transpiler/transpiler/tests/run_gvar_hoisting_tests.cjs (new)

* Refine GVAR hoisting fix: only prevent when GVAR is written

The initial GVAR hoisting fix was too aggressive - it prevented hoisting
ANY expression that read from GVARs, even when those GVARs were never
written. This caused the "duplicate let declarations" test to fail.

Refinement:
- Added findWrittenGvars() to track which GVARs are actually being SET
- Only prevent hoisting if reading from a GVAR that is WRITTEN
- GVARs that are only READ can be safely hoisted

This allows safe optimizations while still preventing the original bug.

Test Results:
- All 28 test suites now pass (was 27/28)
- GVAR hoisting regression tests: PASS
- Duplicate let declarations test: PASS (fixed)
- User's original conditions: PASS

Example distinction:
- gvar[5] only read → hoisting ALLOWED (safe optimization)
- gvar[7] written by LCs → hoisting PREVENTED (prevents bug)

* Add DELAY to stateful operations + implement bot suggestions

1. Exclude DELAY from hoisting (like STICKY/TIMER)
   - DELAY maintains state (timeout, flags) across loop iterations
   - Should not be hoisted to prevent incorrect evaluation timing
   - Updated: identifyHoistedVars, activatorChainHasSticky, findStickyInActivatorChain

2. Add defensive check in decompileTree (Qodo suggestion #1)
   - Prevent crashes from malformed trees with missing node.lc or node.children
   - Adds robustness for edge cases

3. Use enums in test file (Qodo suggestion #2 - partial)
   - Import OPERATION and OPERAND_TYPE constants
   - Replace magic numbers with named constants (first test case)
   - Improves test maintainability

Test Results:
- All 28 test suites pass
- No regressions introduced

* Exclude EDGE from hoisting (stateful operation)

EDGE maintains state (timeout, flags) across loop iterations like
STICKY/TIMER/DELAY, so it should not be hoisted.

Changes:
1. Added EDGE to stateful operations exclusion in identifyHoistedVars()
2. Added EDGE to activatorChainHasSticky() check
3. Added EDGE to findStickyInActivatorChain() for scope detection
4. Removed EDGE from complexOps list (now excluded earlier)
5. Updated edge_activator_in_sticky test to accept both patterns:
   - Hoisted: const cond1 = ... ? edge(...) : 0
   - Inline: on: () => (... ? edge(...) : 0)

Both patterns correctly preserve the activator relationship.

Test Results:
- All 28 test suites pass
- edge_activator_in_sticky test now accepts inline pattern

* Add comprehensive hoisting documentation to activator_hoisting.js

Added detailed header comment explaining:
- What hoisting is and why we do it
- Hoisting criteria (all conditions that must be met)
- Excluded operations (stateful, actions, GVAR dependencies)
- GVAR dependency tracking and why it matters
- Execution order preservation mechanisms
- Example of hoisted code

This helps developers understand the hoisting logic without needing
to read through the implementation.
Fixes JavaScript ReferenceError where code was calling
GUI_control.prototype.log() instead of GUI.log().

GUI_control is a constructor function, while GUI is the
exported singleton instance that should be used throughout
the codebase.

Changed 4 instances in 3 files:
- tabs/magnetometer.js:653 - Magnetometer 3D initialization
- tabs/firmware_flasher.js:829 - Firmware flasher error logging
- js/serial_backend.js:348,416 - Serial connection error logging

All other tabs correctly use GUI.log(). This fix brings
these files in line with the established pattern.

Fixes #11xxx (magnetometer tab initialization error)
Add automatic fallback from hardware to software WebGL rendering
with graceful degradation when WebGL is completely unavailable.

Changes:
- Add tryCreateWebGLContext() helper with 3-tier fallback
- Try hardware WebGL, then software WebGL, then graceful disable
- Show user-friendly messages when 3D unavailable
- Provide no-op functions to prevent crashes
- Add console logging for WebGL rendering method

Fixes crashes when WebGL unavailable in Setup and Magnetometer tabs.
Improves UX for users with GPU driver issues or running in VMs.

Files modified:
- tabs/setup.js: Robust WebGL detection
- tabs/magnetometer.js: Robust WebGL detection
Fixes the "fs is not defined" ReferenceError when saving mission files
from the Mission Control tab.

**Problem:**
- Legacy code was using Node.js fs.writeFile() directly from renderer
- fs module is not accessible in Electron's renderer process
- Users got error: "ReferenceError: fs is not defined" at line 4050

**Solution:**
- Replace fs.writeFile() with window.electronAPI.writeFile()
- Use Promise-based API (.then) instead of callback pattern
- Move success messages inside .then() block to ensure they execute
  after file write completes

**Testing:**
- Configurator builds without errors
- Mission file save dialog opens correctly
- Files save successfully to selected location
- No console errors

Follows the same pattern used in cli.js and other tabs.
The OSD tab only needs to know which Logic Conditions are enabled to
populate dropdown selectors - it never inspects LC content. Replace
the heavyweight loadLogicConditions() call (which fetches up to 64
individual LCs via MSP) with a single MSP2_INAV_LOGIC_CONDITIONS_CONFIGURED
request that returns an 8-byte bitmask.

This also fixes iNavFlight#2552 (LC dropdowns showing "Logic 0") by moving the
mask fetch into the OSD.reload chain so data is available before
createCustomElements() builds the UI.
Use unsigned right-shift (>>>) for bitmask checks to avoid
sign-extension issues when bit 31 is set. Use MSP.promise() with
.catch() so done() is always called even if the mask fetch fails.
Prepare for 9.0.1 patch release.
Built from firmware commit d44f2cf6e6 (maintenance-9.x tip).
Linux x64 built locally for glibc 2.34 compatibility (Ubuntu 22.04+).
All other platforms from CI nightly v9.0.1-20260214.201.
…L binaries

Bump configurator version to 9.0.1
- Add null safety to normalizeTargetName() for failed MSP connections
- Quote CSS attribute value in jQuery selector to prevent breakage
- Show display name (spaces) instead of target_id (underscores) in
  firmware version dropdown placeholder
- De-duplicate release entries when both hyphen and underscore variants
  of the same target exist in a release
…asher-target-matching

Fix firmware flasher board matching for multi-underscore targets
…rsion-9.0.2

Bump configurator version to 9.0.2
…configured-mask

OSD: use LC configured mask
…ave-directory

Remember last save directory across file operations
…set-ui

Add GPS preset UI with auto-detection and M9 Precision/Sport modes
…ing-decompiler-warning

Decompiler: improve handling of garbage input
…on-navigation

Feature: Accordion navigation for tab organization
…ramming-lc-highlighting

JavaScript Programming tab: Add true/false indicators to aid debugging
…ramming-debug-tools-2-3-from-feature-1

JavaScript Programming: Add Code Sync Status and Gvar Display
…-ble-device-chooser-issue-2361

Improve BLE device chooser with sorting and filtering
…ip-ui-redesign-2b

LED Strip UI - Improved Layout
- outputMapping: detect PINIO outputs via specialLabels (firmware-assigned
  USER number) instead of timerOverrides cross-referencing; USER number
  derived directly from specialLabels value (2=USER1, 3=USER2, etc.)
- mixer: label PINIO timer output mode as "PINIO / DUTY CYCLE"
- logicConditions: rename condition 52 from "LED Pin PWM" to "PINIO PWM";
  enable second operand (operandB = duty cycle, operandA = channel index)
- transpiler: rename LED_PIN_PWM to PINIO_PWM throughout; update decompiler
  handler for two-operand pinioPwm(channel, duty) semantics
Fix operand order for backward compatibility: operandA=duty, operandB=pin
(0=LED pin, 1=USER1, 2=USER2, ...). Old LED_PIN_PWM configs with
operandA=duty and operandB=0 continue to work unchanged.

Rename condition label to "PWM on pin" to reflect operand order.

Add pwmOnPin(duty, pin) to JavaScript transpiler with full round-trip
support (compile JS->LC and decompile LC->JS). Function name mirrors
the "PWM on pin" label: duty first, then pin.

Also fix transformBodyStatement to dispatch CallExpression nodes, which
was silently dropping function calls in if-statement bodies.

Add round-trip tests: compile, decompile, and JS->LC->JS for LED pin,
USER1, and USER2.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 7, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
11.3% Duplication on New Code (required ≤ 3%)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@github-actions
Copy link

github-actions bot commented Mar 7, 2026

Branch Targeting Suggestion

You've targeted the master branch with this PR. Please consider if a version branch might be more appropriate:

  • maintenance-9.x - If your change is backward-compatible and won't create compatibility issues between INAV firmware and Configurator 9.x versions. This will allow your PR to be included in the next 9.x release.

  • maintenance-10.x - If your change introduces compatibility requirements between firmware and configurator that would break 9.x compatibility. This is for PRs which will be included in INAV 10.x

If master is the correct target for this change, no action is needed.


This is an automated suggestion to help route contributions to the appropriate branch.

@sensei-hacker sensei-hacker changed the base branch from master to maintenance-10.x March 7, 2026 19:16
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.

3 participants