Skip to content

[EXPERIMENTAL] WASM SITL - Run INAV firmware in browser#44

Draft
sensei-hacker wants to merge 59 commits intomaintenance-9.xfrom
feature/wasm-sitl-squashed
Draft

[EXPERIMENTAL] WASM SITL - Run INAV firmware in browser#44
sensei-hacker wants to merge 59 commits intomaintenance-9.xfrom
feature/wasm-sitl-squashed

Conversation

@sensei-hacker
Copy link
Owner

Summary

This PR adds WebAssembly (WASM) support to INAV SITL, enabling the flight controller firmware to run directly in a web browser.

⚠️ EXPERIMENTAL: Proof-of-concept for testing and feedback.

Features

  • WASM SITL target compiled with Emscripten
  • Byte-level serial interface for MSP communication
  • IndexedDB-based settings persistence
  • WebSocket serial driver for PWA compatibility

Limitations

  • No flight simulation (sensors not connected)
  • Requires companion configurator changes
  • Single-threaded execution

Testing

  • WASM builds with Emscripten ✓
  • Configurator connects via "SITL (Browser)" ✓
  • MSP read/write settings works ✓
  • Settings persist across reloads ✓

Reviewed with inav-code-review agent.

functionpointer and others added 30 commits October 25, 2025 18:35
Quite similar to NEXUSX, but with FrSky built-in receiver
Apparently DSHOT_DMAR can only work with max 4 timers.
With the previous timer setup this caused a limit of 7 motors.
The new setup increases it 9.

However, it costs some flexibility.
The new default config sets up TIM1 as MOTOR by default,
creating sane defaults for platforms with 1 or 4 motors.
The Puya PY25Q128HA is a W25Q128-compatible 128Mbit (16MB) SPI NOR flash
chip. This PR adds detection support by including its JEDEC ID in the flash
configuration table.

Changes:
- Added PY25Q128HA JEDEC ID (0x856018) to m25p16FlashConfig[] array
- Updated Blackbox documentation with PY25Q128HA in supported chips list

The chip uses the same SPI command set as other supported flash chips,
so no driver modifications are required beyond adding the JEDEC ID for
auto-detection during initialization.
This wing target is performance-constrained and wing aircraft typically
don't benefit from dynamic notch filtering, which is primarily designed
for detecting and filtering multirotor motor noise.

Disabling the dynamic notch filter by default reduces CPU overhead
and improves task scheduling margin on this board.
Adds cygwin1.dll to the Windows SITL build artifact so users
don't need Cygwin installed to run the SITL executable.

Cherry-picked from PR iNavFlight#11133.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…disable-dynamic-notch

BLUEBERRYF435WING: Disable dynamic notch filter by default
…-dll

Include cygwin1.dll in Windows SITL artifact
…128ha-flash-support

Add support for Puya PY25Q128HA flash chip
This enables automatic pre-release builds when commits are pushed to
the maintenance-9.x branch, providing complete firmware artifacts for
RC releases.
Problem:
- Field definitions use AT_LEAST_MOTORS_N (checks motorCount AND flag)
- I-frame write used MOTORS (checks flag only)
- When motorCount=0 and flag=true: header declares 0 fields, I-frame writes 1 byte
- motor[0] - getThrottleIdleValue() = 0 - 0 = 0 → encodes as 0x00
- Decoder expects frame marker, finds null byte → catastrophic failure

Fix:
- Change I-frame write from FLIGHT_LOG_FIELD_CONDITION_MOTORS
  to FLIGHT_LOG_FIELD_CONDITION_AT_LEAST_MOTORS_1
- Change P-frame write for consistency
- Now matches field definition condition exactly

Testing:
- Board with motorCount=0, MOTORS flag enabled
- Before: 207 decoder failures (0.050s duration)
- After: 3 decoder failures (12s duration) - matches baseline

Files:
- src/main/blackbox/blackbox.c lines 1079, 1346

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This change makes it easier for users to find and download INAV Configurator
and firmware by adding a dedicated Downloads section near the top of the README.

Previously, download links were buried in the Tools section lower in the document,
requiring users to scroll and search. The new Downloads section appears right
after the Community section, making it immediately visible to new users.

Benefits:
- Reduces user friction - fewer clicks to find downloads
- Improves user experience for new users
- Links use /releases/latest URLs that automatically show the latest version
- Clear instructions to select platform from Assets section

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements pitot sensor validation by comparing hardware pitot readings
against virtual airspeed (GPS + wind estimator). Detects blocked or
failed pitot tubes and automatically falls back to GPS-based airspeed.

Features:
- Compares pitot against virtual airspeed (wind-corrected, not raw GPS)
- Wide thresholds (30%-200%) catch gross failures while avoiding false positives
- Sustained failure detection (1 second) before declaring sensor failed
- Automatic fallback to GPS airspeed when pitot fails validation
- OSD warning displays "PITOT FAIL" when sensor invalid
- Automatic recovery after 0.5 seconds of good readings
- Conservative approach: only validates when GPS available and moving >7 m/s

Safety improvements:
- Detects blocked pitot tubes (forgotten cover, insects, ice)
- Prevents dangerous high gains with invalid pitot data
- Maintains aircraft controllability when pitot fails
- Clear pilot awareness via OSD warning

Addresses GitHub issue iNavFlight#11208
Changes to Airspeed-based PID Attenuation (APA) for fixed-wing aircraft:

1. Reduced I-term scaling aggressiveness
   - I-term now scales with (apa_pow/100 - 1) instead of apa_pow/100
   - Example: apa_pow=120 → I uses 0.20 exponent vs 1.20 for P/D/FF
   - Prevents integral windup and overshoot
   - Follows industry best practice (Betaflight, ArduPilot)
   - Maintains trim stability across speed range

2. Reduced maximum gain increase from 200% to 150%
   - Changed upper constraint from 2.0 to 1.5
   - Prevents excessive gain multiplication at low speeds
   - More conservative approach reduces control sensitivity spikes
   - Still provides adequate authority for slow-speed flight

3. Changed default apa_pow from 120 to 0 (disabled)
   - APA now opt-in for safety
   - Users must explicitly enable after validating pitot sensor
   - Updated description to reflect new behavior
   - Safer default for new users

Control theory rationale:
- P/D/FF scaling compensates for dynamic pressure (½ρV²)
- I-term serves different purpose (steady-state trim)
- Aggressive I scaling causes windup and oscillation
- Conservative I scaling improves control stability

Combined with pitot validation (previous commit), these changes
provide comprehensive safety improvements for APA feature.

Addresses GitHub issue iNavFlight#11208
Clamp airspeed to 100-20000 cm/s (3.6-720 km/h) before using in
power calculations to prevent:
- Division by zero or near-zero values
- NaN results from invalid airspeed readings
- Overflow from extreme values

The constrainf() output clamps are still in place as the final safeguard,
but this prevents bad intermediate calculations.
When hardware pitot fails validation, getAirspeedEstimate() now returns
GPS-based virtual airspeed instead of the corrupted pitot value. This
ensures APA (Airspeed-based PID Attenuation) continues working correctly
with valid airspeed data.

Changes:
- getAirspeedEstimate() falls back to virtual airspeed when pitotHardwareFailed
- Faster failure detection: 0.2s (20 samples) vs 1s (100 samples)
- Slower recovery: 2s of consecutive good readings required
- Separate recovery counter prevents underflow with asymmetric thresholds

Fixes issue where blocked pitot caused APA to use invalid airspeed,
resulting in incorrect PID gain scaling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Increase fw_tpa_time_constant default from 1500 to 2000ms
- Raise airspeed TPA factor upper limit from 1.5 to 2.0
…t-sensor-validation

Adjust TPA parameters for fixed-wing aircraft
Updated fw_tpa_time_constant default value from 1500 to 2000 in Settings.md
to match the authoritative value in settings.yaml. The discrepancy was caused
by the documentation being out of sync with the YAML source.

Regenerated using: python3 src/utils/update_cli_docs.py
…otors-null-bytes

Fix blackbox corruption when no motors defined in mixer
Add optional parameter to MSP_REBOOT (message 68) to trigger DFU mode
directly via MSP protocol. This provides a reliable programmatic method
for tools and scripts to enter DFU mode without CLI timing issues.

Changes:
- Add static variable mspRebootBootloader to store DFU mode flag
- Modify mspRebootFn to use the bootloader flag when calling fcReboot()
- Add mspFcRebootCommand() helper to read optional parameter
- Update mspFcProcessCommand() to handle MSP_REBOOT with new logic
- Update USB Flashing.md documentation with proper CLI sequence
- Add MSP method as recommended approach for programmatic DFU entry

Backwards compatibility:
- Empty payload (existing behavior) = normal reboot
- Parameter 0x00 = explicit normal reboot
- Parameter 0x01 = reboot to DFU/bootloader mode

Tested on AOCODARCF722AIO:
- ✓ Empty payload reboots normally (backwards compatible)
- ✓ Parameter 0x00 reboots normally
- ✓ Parameter 0x01 enters DFU mode (verified with dfu-util)
After moving MSP_REBOOT to mspFcProcessCommand, the mspPostProcessFn
parameter in mspFcProcessOutCommand became unused. Remove it from both
the function signature and call site to fix CI build warnings.
Validate that MSP_REBOOT payload is exactly 0 or 1 byte. Reject
malformed packets with larger payloads to improve protocol robustness.

Suggested-by: qodo-merge bot
sensei-hacker and others added 29 commits January 11, 2026 00:56
- Add missing SERVOS field to blackbox field list
- Fix typo: "blackbox MOTOR" → "blackbox MOTORS"
- Add new "Debug Mode Logging" section explaining debug_mode setting
- Include examples of common debug modes (FLOW_RAW, LANDING, POS_EST, GPS, ALTITUDE)
- Add CLI usage examples for debug mode
- Reference Blackbox Internals.md for technical details
- Mention OSD_DEBUG element for real-time display

This helps users discover the debug logging functionality which was previously only documented in the technical Blackbox Internals document.
Based on qodo-merge bot review suggestion (importance: 7).

Changes:
- Remove static global variable mspRebootBootloader
- Add two distinct post-process functions:
  - mspRebootNormalFn() for normal reboot
  - mspRebootDfuFn() for DFU mode reboot
- Update mspFcRebootCommand() to directly assign function pointer

Benefits:
- Eliminates global state
- Makes control flow more explicit
- Easier to maintain and understand
- Improves code quality per qodo review

Tested on AOCODARCF722AIO hardware:
✅ Backwards compatible reboot (empty payload)
✅ Explicit normal reboot (payload 0x00)
✅ DFU mode reboot (payload 0x01)
…-mode

Add optional DFU mode parameter to MSP_REBOOT command
…ensor-validation

Improve APA safety: pitot validation, reduced gains, safe defaults
…tor-download-links

Add prominent download links to README
…debug-improvements

Improve blackbox DEBUG documentation
8226 deprecated, enum parse fix, enums json
…x-to-nightly

Add maintenance-9.x to nightly build workflow
New target: FrSky/Rotorflight Vantac RF007
Merge accidental master PRs into maintenance-9.x
…-to-authors

Add Ray Morris (Sensei) to AUTHORS
Create automated check that runs on PRs to detect when parameter group
structs are modified without incrementing the version number. This
prevents settings corruption issues like those seen in PR iNavFlight#11236.

Detection logic:
- Scans changed C/H files for PG_REGISTER entries
- Detects struct typedef modifications in git diff
- Verifies version parameter was incremented
- Posts helpful comment if version not incremented

Files added:
- .github/scripts/check-pg-versions.sh - Detection script
- .github/workflows/pg-version-check.yml - Workflow definition
- .github/workflows/README.md - Workflow documentation

The check is non-blocking (comment only) to avoid false positive build
failures, but provides clear guidance on when versions must be incremented.
Improve PG version check robustness and efficiency per Qodo feedback:

1. Struct detection: Use sed/grep pipeline to better filter comments and
   whitespace, reducing false positives. Isolates struct body boundaries
   more reliably before checking for modifications.

2. File iteration: Use while/read loop instead of for loop to correctly
   handle filenames that contain spaces.

3. Workflow efficiency: Capture script output once and pass between steps
   using GITHUB_OUTPUT multiline strings, eliminating redundant execution.

Changes reduce false positives and improve compatibility while maintaining
the same detection logic.
…check-action

Add GitHub Action to detect Parameter Group version increment issues
Replace JavaScript template literals with string concatenation to avoid
YAML parser confusion with template literal interpolation syntax.
GitHub Actions YAML parser can misinterpret template literal dollar-brace
syntax as expression delimiters.
…check-action

Fix YAML syntax error in workflow file
The script now checks the corresponding .h file when PG_REGISTER is in
a .c file but the struct typedef is in the header. This fixes false
negatives where struct changes in headers weren't detected.

Example: blackboxConfig_t is registered in blackbox.c but the struct
typedef blackboxConfig_s is defined in blackbox.h. Previous version
only checked blackbox.c diff and missed the struct field removal.
…ck-struct-fix

Fix PG version check for structs in separate header files
Add CMake infrastructure for building INAV as WebAssembly:
- New wasm.cmake toolchain file for Emscripten compiler
- WASM-specific settings in sitl.cmake (ASYNCIFY, exports, memory growth)
- Build type detection in settings.cmake
- Emscripten SDK path checks in wasm-checks.cmake

This enables building SITL firmware that runs in web browsers.
Modify parameter group system to support WASM lazy allocation:
- Add wasmPgEnsureAllocated() call in PG accessor macros for __EMSCRIPTEN__
- Include wasm_pg_runtime.h header when building for WASM
- Restore ZERO_FARRAY macro in config_streamer_ram.c

In WASM builds, PG memory cannot be allocated by the linker at
compile-time, so accessor macros trigger runtime allocation on
first access.
Integrate WASM support into flight controller core:
- main.c: Call wasmMspProcess() in main loop for MSP handling
- fc_init.c: Initialize WASM PG system and serial port at boot
- fc_core.c: Use emscripten_force_exit() for clean WASM reboot
- config.c: Support WASM PG initialization in config system
- serial.c: Register WASM virtual serial port

These hooks enable the firmware to run as WebAssembly while
maintaining compatibility with native SITL builds.
New serial driver that communicates over WebSocket for SITL:
- Enables configurator PWA to connect to native SITL via WebSocket
- Implements standard serialPort_t interface (read, write, available)
- Supports both WASM and native SITL builds
- Ring buffer based TX/RX with configurable sizes

This allows the web-based configurator to connect to SITL running
either natively (via WebSocket) or in-browser (via WASM).
Complete WASM SITL implementation for running firmware in browsers:

Serial transport (serial_wasm.c/h):
- Virtual serial port with ring buffers for JS<->WASM communication
- Exported functions: serialWriteByte, serialReadByte, serialAvailable
- Interrupt-style callback notification when responses ready

MSP bridge (wasm_msp_bridge.c/h):
- Connects WASM serial port to standard MSP infrastructure
- Reuses existing mspSerialProcessOnePort() - zero MSP code duplication

Parameter group system (wasm_pg_registry.c/h, wasm_pg_runtime.c/h):
- Manual PG registry (linker script not supported in WASM)
- Lazy memory allocation on first PG access
- Handles both system configs and profile arrays

Platform stubs (wasm_stubs.c):
- Stub implementations for hardware-dependent functions
- Time functions using emscripten_get_now()

Target config (target.c):
- WASM-specific target initialization
Testing and development utilities for WASM SITL:

Test harness (src/test/wasm/):
- Browser-based MSP test interface
- Sends MSP commands and displays responses
- Useful for validating WASM build without full configurator

PG registry generator (src/utils/):
- Script to generate wasm_pg_registry.c from PG declarations
- Scans source for PG_REGISTER macros
- Outputs manual registry for WASM builds
Implement persistent storage for WASM SITL settings using browser
IndexedDB. Settings now survive page reloads.

Firmware changes:
- Add wasm_eeprom_bridge.c/h exposing EEPROM buffer to JavaScript
- Add wasmNotifyEepromSaved() callback in config_streamer_ram.c
- Export EEPROM functions and HEAPU8/callMain in cmake/sitl.cmake

The JavaScript side (in configurator) loads stored EEPROM data from
IndexedDB before calling main(), allowing the firmware to initialize
with previously saved settings.
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.

6 participants