Skip to content

Replace hardcoded PX4 firmware lookup with manifest-based discovery#13966

Draft
mrpollo wants to merge 5 commits into
masterfrom
mrpollo/px4_manifest
Draft

Replace hardcoded PX4 firmware lookup with manifest-based discovery#13966
mrpollo wants to merge 5 commits into
masterfrom
mrpollo/px4_manifest

Conversation

@mrpollo
Copy link
Copy Markdown
Member

@mrpollo mrpollo commented Feb 10, 2026

Summary

  • Replace the static px4_board_name_map (60+ hardcoded board ID → firmware name entries) and the GitHub Releases API version detection with dynamic firmware discovery from the PX4 manifest
  • Add a user-selectable firmware build list for PX4 in the upgrade dialog, mirroring the existing ArduPilot combo box pattern
  • Bootloader and canbootloader builds are filtered out from the user-facing list
  • SHA-256 hash verification from the manifest is wired into firmware downloads

Dependency

This PR depends on PX4/PX4-Autopilot#25414 which adds firmware manifest generation to PX4's build system and CI pipeline. That PR creates the manifest infrastructure (per-board metadata, per-release release_manifest.json, and a top-level index.json) that QGC consumes here. The PX4 PR must be merged and at least one tagged release published with the new manifest before this QGC change can be merged.

Currently this PR points at the existing manifest URL (https://px4-travis.s3.amazonaws.com/Firmware/manifest.json) which is already live with format v2 data. The manifest format and URL may be updated as the PX4 PR evolves.

Changes

Commit 1: Manifest parsing backend

  • Remove hardcoded px4_board_name_map and _determinePX4StableVersion() (GitHub Releases API)
  • Add manifest download (_downloadPX4Manifest), parse (_parsePX4Manifest), and data model structs (PX4ManifestBuildInfo_t, PX4ManifestReleaseInfo_t)
  • Add _buildPX4FirmwareHashFromManifest() for firmware URL resolution per board/channel
  • Expose version properties (px4DevVersion, px4ManifestLoaded, px4ManifestDownloading, px4AvailableVersions) to QML
  • Wire SHA-256 hash verification from manifest into _downloadFirmware()
  • Add 5 unit tests covering manifest parsing, version extraction, firmware hash building, missing board handling, and invalid manifest rejection
  • Add test fixture px4_manifest_v2.json with multi-board, multi-channel, bootloader/variant build coverage

Commit 2: User-selectable build list UI

  • Add _buildPX4FirmwareNames() — filters bootloader builds, builds friendly display names, pre-selects _default build
  • Add setSelectedPX4Version() for version picker support in advanced mode
  • Expose px4FirmwareNames, px4FirmwareUrls, px4FirmwareNamesBestIndex to QML
  • Add PX4 firmware selection combo box and version picker to FirmwareUpgrade.qml
  • Refactor onAccepted handler to use flashFirmwareUrl() for PX4 builds
  • Add download status and error labels for PX4 manifest state
  • Add 4 unit tests covering build list generation, bootloader filtering, default pre-selection, and SHA-256 map population

Test plan

  • All 11 unit tests pass (--unittest:PX4ManifestTest)
  • Manual test: plug in Pixhawk → PX4 radio selected → build combo shows filtered list (no bootloaders)
  • Manual test: _default build is pre-selected
  • Manual test: click OK → firmware downloads and flashes successfully from manifest URL
  • Verify ArduPilot firmware selection unchanged (regression)
  • Test with board that has no builds in manifest (graceful "no firmware" message)
  • Test beta/dev firmware type selection updates combo correctly
  • Test advanced mode version picker

@mrpollo
Copy link
Copy Markdown
Member Author

mrpollo commented Feb 10, 2026

Some screenshots

Screenshot 2026-02-10 at 11 17 55 AM Screenshot 2026-02-10 at 11 17 48 AM Screenshot 2026-02-10 at 11 18 17 AM

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 10, 2026

Pre-commit Checks Failed

Status Count
Passed 11
Failed 58
Skipped 3
Hook Results
check yaml...............................................................Passed
check json...............................................................Passed
pretty format json.......................................................Failed
check xml................................................................Passed
check for merge conflicts................................................Passed
check for added large files..............................................Passed
trim trailing whitespace.................................................Failed
fix end of files.........................................................Failed
mixed line ending........................................................Passed
TruffleHog...............................................................Passed
clang-format.............................................................Failed
clang-tidy...............................................................Failed
ruff (legacy alias)......................................................Failed
ruff format..............................................................Failed
pyright..................................................................Failed
shellcheck...............................................................Failed
cmake-format.............................................................Failed
cmake-lint...............................................................Failed
Lint GitHub Actions workflow files.......................................Failed
zizmor (GitHub Actions security).........................................Failed
yamllint.................................................................Failed
markdownlint.............................................................Failed
vale.....................................................................Failed
typos....................................................................Failed
Lint QML files...........................................................Failed
Qt static analysis (clazy)...............................................Passed
Check for Q_ASSERT in production code....................................Passed
Check vehicle null safety................................................Failed
Files Modified by Hooks
 .github/workflows/pr-checks.yml                       |  1 -
 cmake/modules/CPM.cmake                               |  2 +-
 src/Joystick/JoystickManager.cc                       |  1 -
 src/Utilities/Compression/CMakeLists.txt              |  2 --
 src/Utilities/Geo/geographiclib.patch                 |  8 ++++----
 src/Utilities/Geo/ogckml22.xsd                        | 10 +++++-----
 src/Vehicle/FactGroups/VehicleGPSAggregateFactGroup.h |  2 +-
 src/pch.h                                             |  2 +-
 test/AnalyzeView/CMakeLists.txt                       |  1 -
 9 files changed, 12 insertions(+), 17 deletions(-)

How to Fix

./tools/pre-commit.sh
git add -u && git commit --amend --no-edit

Run ID: 21894206095

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 10, 2026

Build Results

Platform Status

Platform Status Details
Linux Passed View
Windows Passed View
MacOS Passed View
Android Passed View

All builds passed.

Test Results

linux_gcc_64: 0 passed, 0 skipped

Total: 0 passed, 0 skipped

Code Coverage

Coverage: 100.0%

No baseline available for comparison

Artifact Sizes

Artifact Size
QGroundControl-aarch64.AppImage 187.88 MB
QGroundControl-installer-AMD64-ARM64.exe 74.93 MB
QGroundControl-installer-AMD64.exe 162.98 MB
QGroundControl-installer-ARM64.exe 75.89 MB
QGroundControl-mac.apk 129.39 MB
QGroundControl-windows.apk 129.38 MB
QGroundControl-x86_64.AppImage 175.71 MB
QGroundControl.apk 292.28 MB
QGroundControl.dmg 313.10 MB

No baseline available for comparison

Updated: 2026-02-11 06:42:04 UTC • Triggered by: Android

Replace the static px4_board_name_map and GitHub Releases API version
detection with dynamic firmware discovery from the PX4 manifest at
https://px4-travis.s3.amazonaws.com/Firmware/manifest.json (format v2).

This removes the need to manually maintain board ID to firmware name
mappings and supports all boards published in the PX4 manifest
automatically.

Changes:
- Remove hardcoded px4_board_name_map (60+ entries) and the GitHub
  Releases API call (_determinePX4StableVersion)
- Add manifest download, parse, and data model structs
  (PX4ManifestBuildInfo_t, PX4ManifestReleaseInfo_t)
- Add _downloadPX4Manifest(), _parsePX4Manifest(), and
  _buildPX4FirmwareHashFromManifest() for firmware URL resolution
- Expose version properties (px4DevVersion, px4ManifestLoaded,
  px4ManifestDownloading, px4AvailableVersions) to QML
- Wire SHA-256 hash verification from manifest into firmware downloads
- Add unit tests for manifest parsing, version extraction, firmware
  hash building, missing board handling, and invalid manifest formats
- Add test fixture (px4_manifest_v2.json) with multi-board,
  multi-channel, bootloader/variant build coverage

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Add a firmware selection combo box for PX4 that lets the user choose
from available builds for their board, mirroring the existing ArduPilot
firmware selection pattern.

The manifest contains multiple build variants per board (default, rover,
fixedwing, etc.) alongside bootloader images. This change filters out
bootloader/canbootloader builds, presents the remaining variants in a
combo box, and pre-selects the _default build.

Controller changes:
- Add _buildPX4FirmwareNames() to populate build list from manifest,
  filtering bootloader builds and building friendly display names
- Add setSelectedPX4Version() for version picker support
- Expose px4FirmwareNames, px4FirmwareUrls, px4FirmwareNamesBestIndex
  properties to QML
- Wire build list refresh on bootloader detection, firmware type
  change, manifest load, and version selection

QML changes:
- Add PX4 firmware selection combo box (px4FirmwareSelectionCombo)
- Add PX4 version picker combo for advanced mode
- Add download status and error labels for PX4 manifest state
- Refactor onAccepted to use flashFirmwareUrl() for PX4 builds
- Rename "PX4 Pro" to "PX4 Autopilot" in radio button label

Tests:
- Add _testBuildPX4FirmwareNames for name/URL/count verification
- Add _testBootloaderFilteredOut for bootloader exclusion
- Add _testDefaultBuildPreSelected for best-index logic
- Add _testSha256MapPopulation for hash map verification

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Replace all px4-travis.s3.amazonaws.com references with the new
artifacts.px4.io CloudFront distribution. This covers the PX4 manifest
URL, SiK radio firmware URLs, and test fixtures. The SiK radio
hm_trp URL is also upgraded from http to https.

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
@mrpollo mrpollo force-pushed the mrpollo/px4_manifest branch from c435bac to fa10ba3 Compare February 10, 2026 21:11
@github-actions github-actions Bot added size/XL and removed size/L labels Feb 10, 2026
@hamishwillee
Copy link
Copy Markdown
Collaborator

@mrpollo Looks pretty cool. What happens in airframe selection - i.e. if you have rover, are you only shown Rover frames?

@mrpollo
Copy link
Copy Markdown
Member Author

mrpollo commented Feb 10, 2026

@hamishwillee I haven't arrived there yet, hopefully it only displays rover frames? I'll check and confirm!

@hamishwillee
Copy link
Copy Markdown
Collaborator

@hamishwillee I haven't arrived there yet, hopefully it only displays rover frames? I'll check and confirm!

Me too, but I suspect not. Either way this is all a change to the UI which will need to be documented in both QGC (first) and PX4 docs. I'm not too involved in the QGC docs anymore but this particular case will need to be done.

@dakejahl
Copy link
Copy Markdown
Collaborator

@mrpollo Looks pretty cool. What happens in airframe selection - i.e. if you have rover, are you only shown Rover frames?

@hamishwillee I haven't arrived there yet, hopefully it only displays rover frames? I'll check and confirm!

The other issue here is that QGC has it's own list of available airframes, which may or may not be present in the firmware ROMFS. A user can select a non-existent airframe and only finds out later, this gets reported frequently. Long term I think we should remove all these baked-in aiframes from ROMFS, in a deployed system only one airframe file is ever used and the rest are bloat. Perhaps a follow-on to this work would be an airframe manifest, or airframe database (like how betaflight does it) where users can download a "preset" (airframe file) specific to their vehicle. This would allow us to host and make available an arbitrary number of airframe files.

@mrpollo
Copy link
Copy Markdown
Member Author

mrpollo commented Feb 10, 2026

@dakejahl thats a neat idea, right now the *.px4 file also has this info baked in, perhaps we can use this for now? beyond that, I can add an extra field to the manifest for a board that includes this info too, many sources to download from now that we have this manifest stuff

@hamishwillee
Copy link
Copy Markdown
Collaborator

hamishwillee commented Feb 11, 2026

FWIW we'd probably be best off supplying the supported airframes as component metadata - perhaps created initially at build time using information in our config files (do we need to think about adding airframes dynamically via SD?). That way you install the firmware you want - "multicopter" and get the frames that make sense for that firmware.

Short term you could probably hard code this mapping in QGC based on the filename variant of the firmware.

Alternatively, invert behaviour such that the user selects an airframe, and from that the firmware is chosen. Not sure that makes sense though, since not all firmwares are airframes, and by the time you have selected your firmware now, you are only interested in the particular relevant subset of frames.

@dakejahl
Copy link
Copy Markdown
Collaborator

"multicopter" and get the frames that make sense for that firmware.

do we need to think about adding airframes dynamically via SD?

One of these. Either we decide that copter get's a handful of copter specific airframes or we decide that copter only gets the base airframe file (rc.mc_defaults) and any further configuration lives in an airframe file on the SD card. The QGC UI would allow downloading airframes files to the SD card (download from server and then push via mavlink FTP).

Compute and store the SHA-256 hash of PX4 firmware images after
decompression (before 4-byte padding) so it can be verified against
the manifest-provided sha256sum. This catches corrupted downloads
that would otherwise only fail at flash time.

Also enrich the test fixture with manifest v2 nested objects
(firmware_category, label_pretty, hardware info) to match the
real PX4 manifest format and support category-based filtering
and build variant tests.

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Replace the confusing channel/version combo in PX4 advanced mode
with two purpose-built dropdowns: a version selector (filtered by
connected board, annotated with channel) and a build variant
selector (filtered by board + version). This mirrors how the
manifest actually organizes firmware and removes the version
dropdown that showed all versions regardless of channel.

- Add _buildPX4AdvancedVersions() to filter versions by board
- Add _buildPX4AdvancedBuildNames() to filter builds by version
- Add setSelectedPX4AdvancedVersionByIndex() for QML interaction
- Add px4AdvancedSelectedChannel() for beta/dev warning display
- Add "Custom firmware file..." button in advanced mode
- Add manifest download retry button for network failures
- Fix custom firmware cancel leaving user stuck at plug-in screen
- Hide old channel dropdown and unfiltered version combo for PX4
- Normal mode and ArduPilot advanced mode unchanged
- Add 4 new unit tests covering all advanced mode methods

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
@mrpollo
Copy link
Copy Markdown
Member Author

mrpollo commented Feb 11, 2026

So I spent a few hours trying to improve the UX for the firmware setup, and its much better now, I was able to create a fake manifest with the updated pretty labels from the recent discussion in the PX4 manifest PR, and incorporated here with pretty good results.

But before that, I also realized we didn't go anywhere with the hash verification before, so I fixed that.

Add SHA-256 verification for decompressed firmware images

  • Computes SHA-256 of the decompressed firmware image (before 4-byte padding) and verifies it against the manifest's sha256sum field
  • Catches corrupted downloads that would otherwise only fail at flash time
  • Enriched the test fixture with manifest v2 nested objects (firmware_category, label_pretty, hardware info) to match the real
    PX4 manifest format

Redesign PX4 advanced mode with version and build dropdowns

The old Advanced mode had a confusing UX: a channel dropdown (Stable/Beta/Dev/Custom) plus a version dropdown that showed all versions
regardless of channel. The new design replaces this with:

  1. Version dropdown — filtered to only show versions that have builds for the connected board, annotated with channel (e.g.
    v1.15.2 (stable), v1.16.0-beta1 (beta)). Latest stable is pre-selected.
  2. Build variant dropdown — filtered by board + selected version. Shows just the label (e.g. "Default", "Multicopter", "Rover")
    without repeating the version tag. Pre-selects Default > Multicopter > _default filename.
  3. "Custom firmware file..." button — always visible in advanced mode. Fixed a bug where cancelling the file picker left the user
    stuck at the "plug in your device" screen with no way to re-open firmware selection.
  4. "Retry" button — shown when the PX4 manifest download fails, allowing the user to retry without restarting the workflow.
  5. Beta/Dev warnings — shown inline when the user selects a non-stable version, using the same warning text as before.

Normal mode (Advanced unchecked) is unchanged — still shows the single build variant combo. ArduPilot advanced mode is
unchanged.

4 new unit tests added (20 total, all passing):

  • _testBuildPX4AdvancedVersions — board filtering, channel annotation, stable pre-selection
  • _testBuildPX4AdvancedBuildNames — build filtering, label display without version, dev mode shows all categories
  • _testPX4AdvancedSelectedChannel — channel lookup for warning display
  • _testSetSelectedPX4AdvancedVersionByIndex — index mapping, build list refresh, invalid index handling
Screenshot 2026-02-10 at 9 31 16 PM Screenshot 2026-02-10 at 9 31 21 PM Screenshot 2026-02-10 at 9 31 32 PM Screenshot 2026-02-10 at 9 31 46 PM Screenshot 2026-02-10 at 10 04 19 PM

Re: documentation (@hamishwillee)

Agreed that the UI changes will need documentation updates in both QGC and PX4 docs. Happy to help draft those once this PR stabilizes.


Re: airframes (@hamishwillee, @dakejahl )

I can confirm that even if you install Rover, the full aerial airframe selection is still available, making it pretty confusing!

Screenshot 2026-02-10 at 9 01 22 PM Screenshot 2026-02-10 at 9 01 15 PM

@DonLakeFlyer
Copy link
Copy Markdown
Collaborator

New firmware flash ui looking good so far.

@dakejahl
Copy link
Copy Markdown
Collaborator

I can confirm that even if you install Rover, the full aerial airframe selection is still available, making it pretty confusing!

I think we address that in a separate PR, for the time being it will remain a little confusing (as it has been)

@github-actions
Copy link
Copy Markdown
Contributor

This PR has been automatically marked as stale due to 90 days of inactivity. Please rebase and update if still relevant, or it may be closed in the future.

@github-actions github-actions Bot added the stale label May 14, 2026
@mrpollo mrpollo removed the stale label May 14, 2026
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.

4 participants