Skip to content

Conversation

@sensei-hacker
Copy link
Member

@sensei-hacker sensei-hacker commented Dec 14, 2025

PR Type

Other


Description

This description is generated by an AI tool. It may have inaccuracies

  • Maintenance merge from 9.x branch to master

  • Updates to SITL (Software In The Loop) binaries for multiple platforms (macOS, Linux ARM64, Linux)

  • Russian locale translations updated in messages.json

  • General maintenance and synchronization between branches


Diagram Walkthrough

flowchart LR
  maintenance["maintenance-9.x branch"]
  sitl["SITL Binaries<br/>macOS, Linux ARM64, Linux"]
  locale["Russian Locale<br/>messages.json"]
  master["master branch"]
  maintenance -- "merge" --> sitl
  maintenance -- "merge" --> locale
  sitl --> master
  locale --> master
Loading

File Walkthrough

Relevant files

Lemontree-Softworks and others added 30 commits December 3, 2025 19:32
Reduce MSP requests from 64 to 1+N (mask + configured conditions only).
Requires firmware support for MSP2_INAV_LOGIC_CONDITIONS_CONFIGURED (0x203C).
…optimized-load

Optimize logic conditions loading
Changes Settings.processHtml to call its callback immediately
instead of waiting for all settings to load. This allows tabs
to start rendering while settings populate in the background.

Key changes:
- js/settings.js: configureInputs() now runs async, callback
  fires immediately for progressive rendering
- tabs/osd.js: Added guards in updatePreviews(), updatePilotAndCraftNames(),
  and fillCustomElementsValues() to handle being called before data loads
- tabs/osd.js: Call updatePilotAndCraftNames() from updateAll() to ensure
  it runs after OSD data is available

This significantly improves perceived load time for tabs with many
settings (e.g., OSD tab with 67+ settings).
Apply qodo-merge suggestion: check that customElementItems exists
before entering the inner loop, not just the parent items[i] object.
The settingsPromise is now passed to the processHtml callback, allowing
tabs to optionally await it if they need settings values immediately.
Existing tabs work unchanged - they can simply ignore the parameter.

Also reverts settingsCache.js to match original code structure.
… or master

Replace semver version checks with runtime capability detection for loading
logic conditions. This will allow a newer configurator to work with 9.0.0-RC1 firmware.
ALso nightly firmware build from between 8 and 9.

Always tries the optimized CONFIGURED mask path first (MSP2_INAV_LOGIC_CONDITIONS_CONFIGURED)
Falls back to legacy path (fetch all 64) if:
   - Firmware returns unsupported/empty response
   - No response within 500ms timeout

This approach removes hardcoded version checks (5.0.0, 9.0.0)
…c-conditions

Make optimized logic condition loading compatible with earlier 9.0-RCx or master
- Remove premature loadOsdCustomElements() call during tab init
  (OSD.reload() already calls it in proper sequence)
- Remove premature updatePilotAndCraftNames() call during tab init
  (already added to updateAll() in previous commit)
- Remove explanatory comments (code is self-documenting)
… or master

Replace semver version checks with runtime capability detection for loading
logic conditions. This will allow a newer configurator to work with 9.0.0-RC1 firmware.
ALso nightly firmware build from between 8 and 9.

Always tries the optimized CONFIGURED mask path first (MSP2_INAV_LOGIC_CONDITIONS_CONFIGURED)
Falls back to legacy path (fetch all 64) if:
   - Firmware returns unsupported/empty response
   - No response within 500ms timeout

This approach removes hardcoded version checks (5.0.0, 9.0.0)
The Common Subexpression Elimination (CSE) optimizer incorrectly reused
cached conditions when the underlying variable had been mutated between
uses. This caused incorrect code generation where the second check would
reuse the first condition's result instead of re-evaluating.
Example that was broken:
```javascript
if (gvar[1] < 2) { gvar[1]++; }
if (gvar[1] < 2) { gvar[1]++; }  // This incorrectly reused first check
```
Root causes and fixes:
1. Parser: transformBodyStatement() didn't handle UpdateExpression (++/--)
   inside if bodies, causing them to be silently dropped
2. Optimizer: CSE cache wasn't invalidated when variables were mutated
   in statement bodies
3. Analyzer: detectConflicts() incorrectly grouped separate if statements
   with the same condition, causing spurious "Multiple assignments" warnings
Changes:
- parser.js: Handle UpdateExpression in transformBodyStatement()
- optimizer.js: Add findMutatedVariables(), invalidateCacheForVariable(),
  and conditionKeyReferencesVariable() to track mutations and invalidate
  affected cache entries after processing each statement
- analyzer.js: Use unique keys per if statement (by index) instead of
  grouping by condition, fixing spurious assignment conflict warnings
- action_generator.js: Pass conditionGenerator reference for additional
  codegen-level cache invalidation
- codegen.js: Pass conditionGenerator to ActionGenerator context
- condition_generator.js: Add invalidateCacheForVariable() and
  cacheKeyReferencesVariable() for runtime cache invalidation
Test coverage:
- test_cse_mutation_bug.js: 6 tests covering increment, assignment,
  pre-increment, unrelated mutation (should NOT invalidate), multiple
  mutations, and complex expressions
Add full support for programming PID controllers (pid[0] through pid[3])
in the JavaScript transpiler. INAV exposes only the output property via
logic conditions (operand type 6).
Changes:
- codegen.js: Add pid[N] and pid[N].output parsing in getOperand()
- decompiler.js: Convert PID operands to pid[N].output syntax
- decompiler.js: Auto-import pid when PID operands are detected
- property_access_checker.js: Validate pid[0-3] array access
Usage:
  // Both forms are equivalent (like rc[N] and rc[N].value)
  gvar[0] = pid[0].output;
  gvar[0] = pid[0];
  // Use in conditions
  if (pid[0] > 500) {
    gvar[1] = pid[0] + 100;
  }
CLI command "logic 0 1 -1 14 6 3 0 3000 0" now decompiles to:
  gvar[0] = (pid[3].output + 3000);
Improves decompilation quality by distinguishing between:
- Boolean operations (EQUAL, GT, LT, AND, OR, etc.) - chain in if() conditions
- Value operations (ADD, SUB, MUL, DIV, MIN, MAX) - inline as expressions
- Action operations (GVAR_SET, OVERRIDE_THROTTLE) - output as statements
Changes:
- decompiler.js: Add isBooleanOperation() to classify operation types
- decompiler.js: Only chain boolean conditions with &&, skip value computations
- decompiler.js: Inline value computations when referenced, even with activators
- decompiler.js: Fix gap marker handling in orphan detection loop
- action_decompiler.js: Fix OVERRIDE_THROTTLE to use operandA (not operandB)
Before: All non-action LCs were &&'d together creating invalid conditions
After: Value computations are properly inlined into expressions
Example improvement:
  Before: override.throttle = 0;
  After:  override.throttle = Math.max(Math.min(1800, ((pid[3].output + 3000) / 2)), ...);
Major refactor of the decompiler to use tree-based rendering instead of
flat group processing. This properly handles INAV's activator model where
LCs with the same activator run in parallel, not as AND chains.
Key changes:
Decompiler architecture:
- New decompileWithTrees() replaces groupConditions/decompileGroup
- buildConditionTree() creates hierarchical {lc, children} structure
- decompileTree() recursively renders with proper nesting
- detectSpecialPatternForNode() identifies EDGE/STICKY/DELAY/TIMER
Sticky syntax - all stickys now use variable + if style:
  latch1 = sticky({
    on: () => condition1,
    off: () => condition2
  });
  if (latch1) { /* body */ }
Benefits:
- Consistent style for all stickys
- Clear separation of state definition vs usage
- Referenced stickys shown even without action children
- Matches mental model of stateful latch
Other improvements:
- EDGE/DELAY rendered as function calls: edge(cond, 100)
- DELTA rendered as delta(value, threshold)
- Arithmetic simplification: x + 0 → x, x * 1 → x
- NOT operator precedence fix: !(complex expr)
- GVAR action refs shown as gvar[N] not logicCondition[N]
Test updates:
- Warning tests use invalid type (99) instead of PID (now supported)
- Chained condition tests expect nested ifs instead of && chains
Expression hoisting for deeply nested function calls:
- Extracts inner Math.round/min/max calls to descriptive variables
- Triggers when nesting depth exceeds 3 levels
- Variable names: rounded, clamped, bounded, floored, ceiled, absolute
- Deduplicates identical expressions (reuses same variable)
- Removes superfluous outer parentheses from assignments
Before:
  gvar[0] = (Math.min(110, Math.max(0, Math.round((rc[12] - 1000) * 110 / 1000))) * 28);
After:
  let rounded = Math.round((rc[12] - 1000) * 110 / 1000);
  gvar[0] = Math.min(110, Math.max(0, rounded)) * 28;
Other changes:
- Sticky latch declarations now use 'var' instead of 'let' to allow
  reassignment (transpiler requires 'var' for mutable variables)
- Multi-line action output (hoisted vars + assignment) properly indented
Adds nested 'mode' object to flight API allowing code like:
  if (flight.mode.poshold === 1) { ... }
  if (flight.mode.rth) { ... }
This uses OPERAND_TYPE.FLIGHT_MODE (type 3) instead of OPERAND_TYPE.FLIGHT,
mapping to INAV's logic condition flight mode operands.
Available modes:
- failsafe, manual, rth, poshold, cruise, althold
- angle, horizon, air, acro, anglehold
- courseHold, waypointMission
- user1, user2, user3, user4
This fixes the decompiler/compiler round-trip where decompiled code
containing flight.mode.* couldn't be recompiled.
This commit enables decompiled JavaScript code to compile back to
logic conditions (round-trip support). Key fixes:
Compiler improvements:
- parser.js: Add StickyAssignment node type, preserve CallExpression
  AST for function calls in arithmetic expressions
- codegen.js: Track latch variables with latchVariables Map, generate
  STICKY logic conditions from sticky() calls, handle nested stickys
- condition_generator.js: Add edge() and delta() handlers for sticky
  on/off conditions, resolve latch variable references to LC indices
- arrow_function_helper.js: Preserve CallExpression in transformCondition
- expression_generator.js: Add Literal, Identifier, MemberExpression
  cases to expression type switch
Decompiler improvements:
- decompiler.js: Skip conditions consumed by STICKY/EDGE/DELAY siblings,
  prevent duplicate variable declarations
- condition_decompiler.js: Remove unsupported Math.round() from
  MAP_INPUT/MAP_OUTPUT (INAV integer division truncates)
- action_decompiler.js: Update hoisting patterns to exclude Math.round
Tests:
- Add 3 new tests for duplicate sticky and empty block prevention
- All 126 transpiler tests pass
The full jetrell-logic.txt now round-trips successfully:
decompile → 37 commands → recompile → 37 commands
This commit fixes several issues with compiling decompiled JavaScript
code that contains sticky assignments inside if blocks.
Parser fixes:
- parser.js: Recognize var latch = sticky({...}) in variable declarations
- parser.js: Add VariableDeclaration support in transformBodyStatement()
Analyzer fixes:
- analyzer.js: Add StickyAssignment case to analyzeStatement()
- analyzer.js: Add handleStickyAssignment() to register latch variables
- variable_handler.js: Add addLatchVariable() for sticky state variables
Codegen fixes:
- codegen.js: Pass activatorId to generateStickyAssignment()
- codegen.js: generateStickyAssignment() now properly inherits activator
Decompiler fixes:
- decompiler.js: reconstructVarVariables() skips latch variables to
  avoid duplicate declarations (latch vars use sticky declarations)
Tests:
- Added test for nested sticky compilation with correct activators
- All 27 decompiler tests pass, 127+ total transpiler tests pass
Example that now works:
  if (flight.gpsValid === 1) {
    var latch1 = sticky({on: () => ..., off: () => ...});
    if (latch1) { gvar[0] = 1; }
  }
This commit fixes several issues that caused decompiled code to compile
incorrectly on subsequent round-trips.
Parser fixes (parser.js):
- Add BinaryExpression handling in extractValue() to compute constant
  expressions like (50 * 28) at parse time
- Add CallExpression handling for Math.min/Math.max expressions
Arrow Function Helper fixes (arrow_function_helper.js):
- Add BinaryExpression handling in extractValue() for expressions in
  arrow function conditions like () => flight.airSpeed > (50 * 28)
Condition Generator fixes (condition_generator.js):
- Fix gvar truthy checks: gvar[0] now compiles to NOT(gvar[0] === 0)
  instead of gvar[0] === 1, which correctly handles any non-zero value
  as truthy rather than only checking for value 1
Condition Decompiler fixes (condition_decompiler.js):
- Fix NOT simplification: !(x === 0) now correctly simplifies to x
  (truthy check), not !x (falsy check) - these have opposite semantics
- Fix double negation: !(!x) correctly simplifies to x
- Preserve correct semantics for falsy vs truthy checks
Decompiler fixes (decompiler.js):
- Skip latch* variables in reconstructVarVariables() to avoid outputting
  stale latch variable declarations from previous compilations
All 127+ tests pass.
This commit fixes two issues that caused "Variable already declared"
errors when recompiling decompiled JavaScript code:
1. Sticky variable declarations now use inline syntax:
   - Changed renderStickyWithLatch() to output "var latch1 = sticky({...})"
     instead of just "latch1 = sticky({...})"
   - Removed generateStickyVarDeclarations() function entirely
   - Sticky variables are now declared at their point of use
2. Let variable declarations skip duplicates from hoisting:
   - generateBoilerplate() now filters let declarations from variableMap
     if the body already contains a declaration for that variable
   - Prevents duplicate "let clamped" from both variableMap and
     expression hoisting
Also adds toMatch() assertion to the test runner for regex matching.
Tests added:
- "should use inline var declarations for sticky"
- "should not produce duplicate let declarations from variableMap and hoisting"
All 29 decompiler tests pass, round-trip compilation verified with
complex jetrell_logic test case (48 commands).
Changed the decompiler to output explicit comparisons for clearer,
simpler round-trip compilation:
- `gvar[0]` (truthy) now outputs as `gvar[0] !== 0`
- `!gvar[1]` (negated truthy) now outputs as `gvar[1] === 0`
This simplifies both compiler and decompiler:
- Compiler: explicit comparison generates 1 LC (GREATER_THAN or EQUAL)
  vs truthy which generates 2 LCs (EQUAL + NOT)
- Decompiler: direct output vs pattern detection to simplify NOT(x===0)
The explicit syntax is also semantically unambiguous - truthy could
mean either "!= 0" or "=== 1" depending on context.
Consolidates duplicated code from parser.js and arrow_function_helper.js
into a single expression_utils.js module.

Changes:
- New: expression_utils.js with extractValue(), extractIdentifier(),
  and createExtractionHelpers() functions
- parser.js: Delegates to shared implementation, adds CallExpression hook
- arrow_function_helper.js: Delegates to shared implementation
- New: 34 tests covering all cases in expression_utils.test.cjs

This addresses Item #1 from the transpiler simplification review.
Reduces ~150 lines of duplicated code to a single shared module.

All 34 expression_utils tests pass
All 29 decompiler tests pass
All 37 variable_handler tests pass
All 14 let_integration tests pass
Removes 240 lines of unused code that was replaced by the tree-based
decompiler (decompileWithTrees):

- collectDescendants() - only called from groupConditions()
- groupConditions() - never called
- decompileActionOrCondition() - only called from decompileGroup()
- decompileGroup() - never called

These were remnants of the older group-based decompilation approach.
The tree-based approach provides better output and is what's currently used.

All 29 decompiler tests pass.
Decompiler (121 lines):
- detectSpecialPattern() - was used by removed decompileGroup()
- isVarInitialization() - was used by removed groupConditions()
- Updated stale comment referencing removed generateStickyVarDeclarations()

Analyzer (9 lines):
- serializeCondition() - never called

All 29 decompiler tests pass.
Co-authored-by: TelegaOvoshey <[email protected]>
- Add PID controller output examples (pid[0-3].output)
- Add flight mode detection examples (flight.mode.*)
- Update sticky examples to use variable assignment syntax
- Add mode-based VTX control example
- Add sticky with variable reuse example
sensei-hacker and others added 29 commits December 19, 2025 20:38
The blackbox tab was using the deprecated fs.writeFileSync()
which is not available in the Electron renderer process due to context
isolation. Updated to use the secure window.electronAPI.appendFile()
method exposed through the preload script.

Changes:
- Replace fs.writeFileSync() with window.electronAPI.appendFile()
- Add proper error handling with GUI feedback
- Use Promise-based async flow for file writing

This brings the code in line with other tabs (cli.js, logging.js) that
already use the electronAPI correctly.
Fixes four bugs that prevented the auto-select target feature from working correctly:

1. Board selection handler using .text() instead of .val() (line 326)
   - The releases object is keyed by value (raw_target), not display text
   - This caused releases[target] lookups to fail, leading to forEach errors

2. Missing safety check before forEach (line 342)
   - Added check to prevent crash when releases[target] is undefined
   - Handles cases where board has no available firmware releases

3. Inefficient board selection code (line 864)
   - Changed from broken attribute selector to .val() method
   - More reliable and cleaner implementation

4. Trigger change only when board found (line 872-873)
   - When detected board isn't in list (e.g., unstable release filtered out),
     .val() fails silently but change event still triggered with null
   - This caused "{-1}" to appear in firmware version dropdown
   - Now only triggers change if board was successfully selected

Tested with both stable and unstable release filters enabled/disabled.
Convert JavaScript Programming transpiler from destructuring-based
syntax to fully namespaced API:

- Update all 22 examples to use inav.flight.*, inav.override.*, etc.
- Add support for inav.events.edge() and inav.events.sticky()
- Implement dispatch tables for cleaner handler routing
- Add namespace normalization across parser, codegen, analyzer
- Update default templates and quick reference examples
- Maintain backward compatibility with old syntax

This improves Monaco editor autocomplete support and provides
a cleaner, more discoverable API for users.

Changes:
- parser.js: Recognize inav.events.* function calls
- codegen.js: Event handler dispatch table, operand normalization
- decompiler.js: Pattern renderer dispatch table
- analyzer.js: Assignment target normalization
- action_generator.js: Action target normalization
- property_access_checker.js: API validation with dispatch tables
- examples/index.js: All examples updated to namespaced syntax
- tabs/javascript_programming.*: Default templates updated
Support both rc[N].low/mid/high and inav.rc[N].low/mid/high syntax
in condition generator for member expression handling.
New script tests that all examples in examples/index.js compile
successfully. Provides quick validation that the transpiler works
with all user-facing examples.
Fix variable handler to detect inav.gvar[N] in addition to gvar[N]
when identifying explicitly used gvar slots. This ensures var variables
avoid collisions with explicitly referenced gvar slots in user code.

Fix action decompiler RC channel override output to include inav. prefix
(inav.rc[N] = value) for consistency with other decompiled output.

Update all test files to use fully namespaced syntax:
- inav.flight.* instead of flight.*
- inav.gvar[N] instead of gvar[N]
- inav.rc[N] instead of rc[N]
- inav.override.* instead of override.*
- inav.events.edge() instead of edge()
- inav.events.sticky() instead of sticky()

All 25 test suites now pass.
Complete the namespace refactoring by adding inav. prefix to the
remaining operand types in the decompiler's operand-to-string conversion:

- gvar[N] → inav.gvar[N]
- rc[N] → inav.rc[N]
- pid[N].output → inav.pid[N].output

This matches the changes already made to action_decompiler.js and ensures
all decompiled output uses the fully namespaced syntax consistently.
Add xor, nand, nor, and approxEqual to the helpers.js API definition
alongside the existing mapInput and mapOutput functions.

Update condition_generator.js and expression_generator.js to:
- Extract function names from both simple calls (xor()) and namespaced
  calls (inav.helpers.xor())
- Validate that namespaced calls use the correct inav.helpers.* namespace
- Reject invalid namespaces like inav.pid[0].mapInput() with clear error
  messages

This prevents nonsensical function calls from silently succeeding and
ensures all helper functions are properly namespaced for consistency
with the rest of the INAV API.

Backward compatibility: Global function calls (xor(), mapInput(), etc.)
continue to work for existing user code.
Changed extractHelperFunctionName() to return null for invalid namespaces
instead of returning an object with invalidNamespace flag. This matches the
pattern used in condition_generator.js.

Now inav.pid[0].mapInput() correctly produces 'Unknown function call' error
instead of the confusing 'Helper function must be called as...' error.

The function now:
- Returns function name string for valid calls (mapInput() or inav.helpers.mapInput())
- Returns null for invalid namespaces (inav.pid[0].mapInput())
- generateCall() treats null as 'not a helper function' with generic error
Removed extractHelperFunctionName() methods from both condition_generator.js
and expression_generator.js. Inlined the namespace checking directly in
generateCall() for better clarity and efficiency.

Benefits:
- More explicit: only checks namespace when callee.object.property.name === 'helpers'
- More efficient: avoids function call overhead for non-helper namespaces
- Clearer code flow: namespace check is inline with its usage
- Consistent pattern: both generators use the same approach

Pattern:
  // Backward compat: funcName()
  if (callee.type === 'Identifier') {
    funcName = callee.name;
  }
  // New syntax: inav.helpers.funcName()
  else if (callee.object?.property?.name === 'helpers') {
    funcName = callee.property?.name;
  }

For invalid namespaces like inav.pid[0].mapInput(), funcName remains null
and produces 'Unknown function call' error.
Changed from prefix matching ('gvar[', 'rc[', 'events.', 'helpers.') to
namespace extraction for cleaner, more consistent routing.

New approach:
1. Extract namespace (first word before . or [)
2. Route to namespace-specific handler based on extracted namespace
3. Special handlers only for array-based properties (gvar, rc, pid)
4. Generic handler for all other namespaces (flight, override, helpers, events, waypoint)

Benefits:
- Consistent routing logic across all namespaces
- No special cases for helpers/events vs other API properties
- Easier to understand: if (namespace === 'gvar') vs if (path.startsWith('gvar['))
- All API properties validated the same way through checkApiPropertyAccess()

Before: Used prefix matching with special empty handlers for helpers/events
After: Extract namespace, route consistently to special or generic handler
Added new test suite to verify consistent namespace-based routing:

Tests cover:
- Helper function calls: inav.helpers.mapInput() vs mapInput() (backward compat)
- Invalid namespace rejection: inav.pid[0].mapInput() should fail
- Property access validation for all namespaces (flight, override, gvar, rc, pid)
- Array index validation (gvar, rc, pid)
- Invalid namespace detection

Also added run_all_tests.cjs script to execute complete test suite.

All 26 test suites pass (25 existing + 1 new with 15 test cases).
Fixes Qodo comment #2 from PR #2490.

Previously, flight axis overrides with unprefixed syntax (e.g.,
override.flightAxis.roll.angle) failed because the regex in
action_generator.js matched against the raw target instead of
normalized target. This broke backward compatibility.

Changes:
- action_generator.js: Normalize target before regex matching
- property_access_checker.js: Accept both prefixed and unprefixed targets
- codegen.js: Normalize target in getOverrideOperation()
- Added comprehensive test suite for flight axis overrides

All 27 test suites passing.
The main process appendFile() handler throws/rejects on error, not
resolves with an error object. The previous code checking `if (err)`
in the .then() callback would never catch errors.

This fixes the bug by properly using .catch() to handle rejections.

Addresses Qodo code review suggestion #1.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
…tenance-9x

Fix blackbox save to file functionality
Replace strict truthy check with duck typing that verifies the forEach
method exists and is callable. This is more flexible and future-proof:
- Works with arrays, NodeLists, and any iterable with forEach
- More JavaScript-idiomatic (duck typing over type checking)
- Focuses on behavior ("can iterate?") not type ("is Array?")
- Uses optional chaining (?.) for modern, concise code

Benefits over Array.isArray():
- If data structure changes to Set, NodeList, or custom collection,
  code continues to work without modification
- More aligned with JavaScript best practices
- Clearer intent: we care about iteration capability, not array type
…reach

Fix auto-select target functionality in firmware flasher
…ns-9-rc3

Add missing ukrainian translations 9 rc
Two fixes for intermittent connection failures:

1. Fix error handler in serial.js to correctly report errors
   - The error handler was resolving with {error: false} when there
     was an actual error, causing confusing "connection canceled"
     messages and preventing proper error handling

2. Reset MSP decoder state before adding receive listeners
   - Move FC.resetState() earlier in the connection sequence
   - Add MSP.disconnect_cleanup() to reset decoder state
   - This ensures garbage bytes or boot messages received during
     USB enumeration don't corrupt the MSP decoder state
When serial port errors occurred, the port handle wasn't being properly
cleaned up, leaving zombie handles that blocked reconnection attempts.

Changes:
- Add cleanup in error handler: removeAllListeners() + destroy()
- Make connect() async to properly await cleanup of existing ports
- Add 100ms delay after destroy() to let OS release file handle
- Fix close() race condition: null reference before close callback
- Handle case where port exists but isn't open

This fixes the "Resource temporarily unavailable Cannot lock port"
error that occurred when reconnecting after a connection failure.
…emove-destructuring

Refactor JavaScript Programming to use fully namespaced inav.* syntax
…iability

Fix serial connection reliability issues
Add error callback to MSP.send_message in processNextCondition() so that
if an individual logic condition fetch fails, loading continues with the
next condition rather than halting indefinitely.

Previously, only a success callback was provided, meaning any MSP error
would stop the loading sequence without ever calling the final callback.
…ing-error-handler

Fix logic conditions loading to handle MSP errors
The SITL feature was broken because the code looked for binaries in
the wrong location. The path used __dirname which points to the Vite
build output (.vite/build/), but SITL binaries are in resources/public/sitl/.

Changes:
- Add getSitlBasePath() function that returns correct path based on
  whether app is packaged (process.resourcesPath) or in dev mode
  (app.getAppPath()/resources/public/sitl)
- Add extraResource in forge.config.js to include SITL in packages
- Add afterCopy hook to remove binaries for other platforms/architectures,
  reducing package size
Fix SITL binary path resolution for dev and packaged modes
@sensei-hacker sensei-hacker merged commit 01d957e into master Dec 24, 2025
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants