Homebrew 6.0+ refuses to load formulae from untrusted third-party taps. This adds a trusted block for OSRF taps.
Signed-off-by: Cade Andersen <cadecandersen@gmail.com>
* feat(navigator): extend detect and avoid module to follow regulatory standards such as ASTM F3442
* docs(docs): minor subedit
* refactor(navigator): reduce flash by grouping notif into same events
* docs(daa): Improve docs readability with ::: details blocks
* fix(navigator): single event when on ground with conflict
* refactor(boards): increase flash length from 4M - 128k to 5M - 128k
* rework(general): define DAA standard at build with new CONFIG_NAVIGATOR_ADSB_F3442
* clean(navigator): minor changes to clean the PR
* feat(boards): add CONFIG_NAVIGATOR_ADSB_FAKE_TRAFFIC in visionTargetEstStatic.px4board
* rework(daa): reduce amount of abstractions and minor cleaning
* refactor(boards): allyes revert flash length to 4M-128K
* refactor(boards): allyes increase flash length to 5M-128K
* rework(daa): rework event notifications to improve clarity
* docs(docs): move details inside of ::: details block
* docs(docs): run npx prettier
* refactor(daa): avoid void mutator functions
* docs(docs): Improve Python helper to decode daa unique id
* rework(daa): move encoded id handling to the adsb lib and refactor on_active
* refactor(daa): naming and zero init
* fix(daa): move dataman dep from daa level to unit test level
* refactor(daa): define common daa_input and rework process_transponder_report
* fix(daa): remove stale todo
* refactor(daa): rename crosstrack_based_daa to crosstrack_standard
* refactor(daa): rename F34_ params to DAA_
* docs(docs): revert changes to autogenerated docs
* docs(docs): Add Detect And Avoid in index.md
* refactor(daa): update message on init failed
* refactor(daa): only publish most_urgent conflict once in on_active()
* refactor(daa): move conflict buffer handling in the adsb lib
* refactor(daa): move notifications into new class ConflictNotifier and only notify once per cycle
* refactor(daa): uninit _cycle_changes to store into .bss (and save flash)
* docs(docs): remove unused image link
* refactor(daa): move automated action policy to the adsb lib
* refactor(daa): move self detection into adsb lib as DaaTrafficFilter
* refactor(daa): minor changes in unit tests
* refactor(daa): merge DaaTrafficFilter and DaaEncoding
* fix(daa): fix CI by removing navigator from the DAA deps
* refactor(daa): reduce stack size
* fix(daa): advertise _fake_traffic_pub in constructor
* refactor(daa): Comments only, simplify and reduce comments
* fix(daa): brief comment missing end star
* Disable CONFIG_NAVIGATOR_ADSB in ark_fpv_default board
* docs(docs): General clarifications and remove the 1.18 badge
* refactor(daa): cleaning
* refactor(daa): minor cleaning
* refactor(adsb): simplify conflict tracker assuming push_back cannot fail
* build(cmake): cleaner fix to protect regex alternations
* refactor(daa): Crosstrack, remove unit test requiring finite yaw (yaw not used by standard)
* refactor(daa): minor cleaning and fix callsign to uint64
---------
Co-authored-by: jonas <jonas.perolini@rigi.tech>
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
The --viewer path (tee MAVLink frames to UDP and enable the
HIL_STATE_QUATERNION/HIL_ACTUATOR_CONTROLS streams so Hawkeye could
render an SIH flight live) was never validated end to end: Hawkeye
never actually rendered from it. Rather than ship an unproven feature,
drop it.
Removes px4bench.attach_viewer_tee (and its function-local socket use),
the flight_mission --viewer/--viewer-port args, the viewer tee call and
the stream-enable block, and the now-unused --board-dev arg that only
fed those stream commands. The SIH flight logic, firmware gate,
storage/serial tests, and the arming gate are unchanged. README and the
bench testing docs page drop the Hawkeye section and all --viewer
mentions.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The full-suite persistence check failed on hardware with 'after reboot
SDLOG_UTC_OFFSET = 740 (expected 777)'. Firmware persistence is solid;
this was a test race. A PARAM_SET propagates through the param system
asynchronously, and phase_persistence ran 'param save' on the strength
of the PARAM_VALUE echo alone. When save raced ahead of the commit it
persisted the PRIOR value (740, the last value Phase 2 wrote). The echo
was not even proof of the new value: wait_param_echo returned
seen=[740, 777], a stale queued PARAM_VALUE from Phase 2 having slipped
past drain_param_values.
Make persistence deterministic with two gates instead of timing:
1. After setting the marker, read it back from the board until it reports
MARKER_VALUE (read_until) before saving. This confirms the value is
committed to RAM and trusts the board's read over any stale echo.
2. After 'param save', confirm the saved state with 'param show <name>'
and require the '+' (saved) flag AND the marker value before rebooting
(retry save once first). '*' means unsaved; the test never reboots on
an unsaved marker. Flag columns per src/systemcmds/param/param.cpp:822
(x used, + saved, * unsaved, l locked).
phase_set_readback now also trusts read_until over the echo, so the same
stale-queued-echo does not fail it either; its pass criteria stay the
readback match. Restores in phase_persistence and the final cleanup use
read_until too.
New shared helpers in px4bench.params: read_until(mav, name, expected,
timeout) -> (ok, last_seen), and param_is_saved(shell, name) plus its
parse_param_show() parser for the 'param show' saved flag and value.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
A hardware run exhausted the board's task/fd table after a few probe
cycles: shell open failed while heartbeat still worked, and continued
writes eventually stalled the link. Not a firmware hang, a resource leak
the tooling drove.
The firmware spawns a new nsh task plus two pipes (four fds) on the
first SERIAL_CONTROL write of a session (Mavlink::get_shell) and only
frees them when a SERIAL_CONTROL message arrives with the RESPOND flag
cleared (Mavlink::close_shell). Two tooling bugs combined to leak them:
- MavlinkShell.open() returned True on any buffered byte, including
leftover output from a prior session, so it reported a live shell
without one. It now confirms an actual 'nsh>' prompt or a completed
echo-sentinel round-trip before returning True, keeping the same
timeout-and-report-failure behavior.
- open/close cycles reopened before the single flags=0 teardown was
processed, spawning a second shell before the first was freed. close()
now sends the flags=0 teardown and then briefly drains incoming
SERIAL_CONTROL until quiet (bounded, never a hang) so the firmware
runs close_shell before a caller can reopen.
Lifecycle: every MavlinkShell user now opens one session, runs all its
work on it, and closes it in a finally so no error path leaks a shell.
The SIH flight and storage tests run all their probes on a single shell
(shell_command_exists already takes an open shell); flight_mission no
longer opens a throwaway probe shell separate from the flight session
beyond the unavoidable reboot boundary in enter_sih.
Folds in the sentinel fix (run() sends the echo sentinels on their own
input line, because nsh aborts a ';' chain when a command fails, which
previously lost the sentinel for a failing probe and read as a stall).
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The flight test is now part of the default suite; both the bench README
and the bench testing guide said it ran separately. Update the sequence
description, the risk map and suite tables (storage_stress and
flight_mission rows, serial_loopback for fixtures), the SIH sections
(probe-and-skip, the typed 'arm' confirmation, --allow-arming for
automation), the production section (--allow-arming on the line,
serial_loopback with a jumper on the fixture), and the firmware gate
--build description (bench capability report with variant and config
line recommendations). Storage threshold defaults are justified where
the flags are documented.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The firmware already ships sd_bench, sd_stress, and serial_test; the
suite was not exploiting them.
bench/storage_stress.py joins the default sequence before log_transfer
(storage health first, then the test that depends on storage). It runs
sd_bench with data verification and parses write/read throughput and
fsync latency into named checks with generous FAIL floors (defaults
justified in the README: 100 KB/s write, 200 KB/s read, 500 ms fsync;
a working-but-slow card prints a WARNING instead of flapping), then
sd_stress for file churn with a short default iteration count. Both
phases probe-and-skip independently: a firmware without a command or a
board without an SD card records SKIP with a warning, never FAIL.
bench/serial_loopback.py is a standalone operator/fixture test for
manufacturing: with a TX-RX loopback jumper installed on a chosen UART,
serial_test transmits a known pattern and the session summary
(rx/tx/rx err counts) plus pattern-error lines decide the verdict. Not
in the default sequence because it needs a physical fixture.
The firmware gate's --build path now prints a bench capability report
from one shared table: after reading default.px4board plus the label
overlay (labels merge both, cmake/kconfig.cmake:47-54) it lists whether
the image will contain simulator_sih, sd_bench, sd_stress, and
serial_test and which suite tests will run or skip. For anything
missing it names a sibling variant that has it (exact --target) and
the exact config line, and interactively offers to append the line to
the local board config, stating that the edit is local and uncommitted.
All four options are 'default n' in Kconfig, so the merged .px4board
lines decide presence.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The simulated flight is the only test that exercises commander,
navigator, and land-detector flight logic on real NuttX scheduling;
leaving it out of the default suite meant the most valuable coverage
was routinely skipped. It now runs last in the sequence.
Arming safety gets two explicit paths: on a TTY the operator sees a
prominent warning that the flight controller WILL ARM (simulated
flight, pwm_out_sim replaces the real outputs, board must be bare) and
must type 'arm'; declining records a skip, not a failure. For
automation and manufacturing lines --allow-arming bypasses the prompt,
and a non-TTY run without it skips the flight with a warning naming
the flag.
Before touching any configuration the test probes the live firmware
for the SIH module ('simulator_sih status'; NuttX nsh replies
'nsh: <cmd>: command not found', apps/nshlib/nsh_parse.c) and skips
with a warning when the module is absent.
Shared plumbing in px4bench: EXIT_SKIP (75) recorded as SKIP by the
orchestrator, shell_command_exists() for probe-and-skip, and
arming_gate() used by both the orchestrator flow and the standalone
flight test. Config mutation by the flight test is expected; it
restores the original airframe and SYS_HITL afterwards.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
--target px4_fmu-v6xrt_bench previously skipped the early board_id
check because only bare vendor_model targets were known; a label
selects a .px4board config within the same board, so strip it and
resolve to the board dir. The uploader still enforces board_id against
the bootloader at flash time.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Today's runs executed against whatever firmware happened to be on the
board (an old April build at first) and nothing checked. For a
qualification tool that is unacceptable: before any test starts the suite
now establishes, and can control, exactly which build it is testing.
New px4bench/firmware.py: .px4 metadata parsing and validation (fields
verified against Tools/px_mkfw.py and px4_uploader.py), board identity
via ver all over the nsh shell, flashing through Tools/px4_uploader.py
with streamed output and a hard timeout, HW-arch to build-target
inference by enumerating boards/, an early wrong-board check against
firmware.prototype board_id, and the named firmware_identity check
(git-hash prefix match against the artifact).
run_bench_suite.py preflight supports four firmware sources, all
converging on the same flash + verify path: keep what is on the board
(--any-firmware), flash a local file (--firmware), build the inferred
target from this source tree (--build, --target, --build-timeout), or
download a GitHub release artifact (--release TAG|latest, via gh;
asset naming verified against the v1.17.0 release). --expect-hash
verifies without flashing. Flags are mutually exclusive; with none
given, a TTY gets an operator menu covering the same four sources, and
automation exits with an error before touching the board. The detected
identity is printed, written to firmware.json in the suite report dir,
and stamped into every test's report dir via PX4BENCH_FIRMWARE_INFO.
If the board's mavlink is wedged the uploader cannot soft-reboot it into
the bootloader (hit live today); after repeated reboot attempts the gate
prints an operator instruction to replug USB so the uploader catches the
bootloader at power-on.
sih/flight_mission.py gains a verify-only --expect-hash and stamps the
firmware identity into its report dir; it never flashes.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The README opened by framing the whole suite around one merged PR
series. The value is general: CI never boots NuttX and SITL runs on a
host OS, so defects in boot ordering, link lifecycle, storage, loop
rates, and RTOS-only concurrency are invisible until a board is on a
bench. Reword the introduction around that gap and the timeout-first
design rule instead of the originating incident.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Turn the flat script pile into a standalone project so contributors can
navigate and extend it:
- px4bench/ shared library package: core primitives in __init__ (Reporter,
connect, MavlinkShell, reboot/replug, viewer tee, mavlink status parsers,
pymavlink add_message workaround) plus protocol modules params.py,
missions.py, and ftp.py extracted from the tests. Zero helper duplication
remains across scripts.
- bench/ holds the real-firmware tests (boot_health, reboot_loop,
usb_replug, link_forwarding, param_stress, mission_stress, log_transfer);
sih/ holds the simulated flight (flight_mission), making the
simulation/no-simulation boundary explicit.
- pyproject.toml (px4bench 0.1.0, BSD-3-Clause, pymavlink/pyserial deps,
pyulog extra) so pip install -e Tools/bench_test works; every script
remains directly runnable without installation via a parent-dir path shim.
- README rewritten contributor-first: architecture, per-test justification
tied to the v1.18 risk areas, why pymavlink over MAVSDK, how to add a
test, baseline workflow.
- Consistent CLI surface (shared connection args; --report-dir replaces
log_transfer's --outdir); decorative section banners removed.
All hardware-learned behavior is preserved exactly: param echo drain and
match-by-value, shell sentinel strip-all, the add_message workaround,
explicit param save before reboot, mission clear before upload, RTL in
MAV_FRAME_MISSION, and the post-flight ULog download.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
sih_flight.py switches the board to a SIH airframe (SYS_HITL=2, physics
on the FMU), flies takeoff, a 3-waypoint square, and RTL as an auto
mission, asserting arming, takeoff, waypoint progression, landing, and
auto-disarm with per-phase timeouts, then restores the original config.
Covers the flight-logic paths the bench tests cannot reach; pwm_out_sim
replaces real outputs so nothing is driven on the rails.
--viewer tees every received MAVLink frame to UDP (frame per datagram,
same framing as the SITL viewer channel) and enables the
HIL_STATE_QUATERNION/HIL_ACTUATOR_CONTROLS streams on the board, so
Hawkeye renders the flight live from a serial-connected board.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
First hardware run (fmu-v6xrt over USB, macOS) surfaced three issues:
- param_torture consumed PARAM_VALUE echoes positionally; one duplicate
broadcast desynced every subsequent check. Drain stale messages before
each set and match the echo against the expected value, reporting all
observed values so a genuine wrong-echo bug remains visible.
- the shell sentinel's second safety echo leaked into the next command's
captured output; strip any sentinel line, not just the current one.
- pymavlink 2.4.49 add_message() intermittently crashes with TypeError
when the first message of an instanced type arrives with its instance
field unset; wrap it defensively until fixed upstream.
Full suite now passes 5/5 against fmu-v6xrt.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Semi-automated bench tests for qualifying v1.18 on real Pixhawk-class
hardware after the TSAN/concurrency series (#27606, #27809, #27813).
CI builds NuttX but never boots it, and the failure mode of this class
of regression is a silent hang, not a crash: every operation here has a
hard timeout and a timeout is reported as FAIL naming what stalled.
Tests map to the reworked subsystems: boot_health (WorkQueue/uORB
snapshot with baseline diffing), dual_link_forwarding (nested-send lock
path under simultaneous two-link load), param_torture (set/readback and
reboot persistence on SDLOG_UTC_OFFSET), mission_torture (dataman and
the mission shared-state mutex, 220 items, link alternation),
mavftp_log (logger on/off plus MAVFTP download and ULog verification),
reboot_loop and the operator-assisted usb_replug (mavlink instance and
RAM lifecycle across re-enumeration). run_bench_suite.py orchestrates
the non-interactive tests with a per-test watchdog.
Requires pymavlink/pyserial, pyulog optional. Nothing arms the vehicle.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* refactor(ROMFS): remove trailing zeros from all airframes
* refactor(ROMFS): remove allignment whitespace from all startup scripts
* feat(romfs_pruner): strip end of line comments in startup scripts
and airframes to not waste any flash.
* feat(romfs_pruner): strip inline multi-whitespace
* fix typo
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Homebrew 6.0 (2026-06-11) makes tap-trust mandatory and refuses to load
formulae from untrusted third-party taps. This broke every macOS build:
brew install aborted with "Refusing to load formula px4/px4/fastdds from
untrusted tap px4/px4" before pouring any package, so ccache (and the
rest of the toolchain) was never installed and setup-ccache failed with
"ccache: command not found".
Trust the three required taps non-interactively before installing from
them. Guarded behind a brew trust capability check so older Homebrew,
which has no trust gate, skips it.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Cross-correlation scripts to measure CAN transport delay from flight
logs. Compares CAN sensor signals against the FC's directly-connected
IMU to estimate the total pipeline latency.
- range_sensor_latency.py: cross-correlates range rate with IMU-derived
vertical velocity
- flow_sensor_latency.py: cross-correlates flow sensor gyro with FC gyro
* fix(bootloader): scrub uncorrectable flash ECC errors on STM32H7 before boot
A torn write to a flash row (power lost mid program/erase) can leave it
with inconsistent ECC. On H7 a CPU read of such a row raises an
uncorrectable double-bit ECC error -> bus fault, so the application hard
faults on every boot before printing anything, and only a mass erase
recovers it: reflashing does not, because neither the app nor the
bootloader image touches the parameter sector.
Scan the application and parameter flash with DMA right after clock_init
(a DMA read latches FLASH_SR DBECCERR instead of bus-faulting the CPU)
and erase any sector that holds an uncorrectable error. A corrupt
parameter sector then re-seeds to defaults on the next app boot; corrupt
app flash fails the image check and stays in the bootloader for reflash.
Mirrors ArduPilot's bootloader ECC scrub. H7-gated; the scan runs before
the interface DMA is brought up, so DMA1 stream 0 is uncontended.
* test(tools): add STM32H7 flash ECC fault injection tool
A bench helper that deterministically plants an uncorrectable (double-bit)
flash ECC error on an STM32H7, reproducing the torn-write parameter-store
brick. Used to validate the bootloader ECC scrub and the parameter re-seed
recovery on hardware: plant the fault, then confirm the board boots clean
instead of hard-faulting every boot.
brick_ecc.c is a freestanding stub that double-programs one flash word with
two different single-bit clears (the recipe that yields an inconsistent ECC);
brick_ecc.sh builds it, loads it into AXI SRAM over ST-Link, runs it, and
resets the board. README documents usage and how to retarget another board.
* fix(bootloader): require DMA transfer-complete for a clean ECC scan chunk
The stream self-disables on both transfer-complete and transfer-error.
A non-ECC bus error (unreachable scan buffer, rejected FIFO config)
previously read as a clean chunk, silently turning the scan into a
no-op. Require TCIF so an unread chunk takes the skip-the-scan
fallback instead of passing.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
---------
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
* feat: implemented serial passthrough
* fix: used make format
* fix: changed function order to match other drivers
* fix: moved passthrough from systemcmds to drivers
* fix: renamed BITBANG_TIMER to UART_BITBANG_TIMER
* fix: used make format
* feat: added PASSTHRU_EN guard to start of dshot&pwm_out
* fix: made changing ESC channels more stable
* fix: adjusted naming of guards
* fix: changed include guard of bitbang
* fix: removed unused variable SER_PASS_BAUD
* fix: adjusted comments
* fix: adjusted print_usage() to match other drivers
* fix: remove bitbang_write_byte from public API and some buffer guard
* fix: added Serialpassthrough&Bitbang to exclude list of allyesconfig.py
* fix: added missing flag to print_usage()
tcdrain()/tcflush() in pyserial's POSIX backend raise termios.error,
which derives from Exception rather than OSError, so it slipped past the
`except (OSError, serial.SerialException)` guards in flush() and
reset_buffers(). When the USB CDC node tore down during a
reboot-to-bootloader re-enumeration (reliably reproduced flashing PX4
onto a board running ArduPilot) the raw error escaped every
ConnectionError retry loop and crashed the uploader. Catch termios.error
explicitly so it surfaces as ConnectionError and the existing
identify/reboot retry loops recover.
reboot() also sent REBOOT once and silently swallowed a missing ack,
reporting success even when the board never left the bootloader. Confirm
the reboot via the bootloader's INSYNC+OK ack (sent before it jumps, per
bl.c PROTO_BOOT) or by watching the serial device re-enumerate, and
resend REBOOT if neither is observed.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
PR #27237 added an unconditional verify_signature() step between verify
and reboot, sending the VERIFY_SIG (0x39) opcode on every upload. For
unsigned firmware this injects an unknown opcode into the bootloader
command stream immediately before BOOT; bootloaders that don't silently
ignore it are left out of phase for the BOOT handshake, so the board
intermittently stays in the bootloader after an otherwise-successful
flash (app LEDs never come on).
Gate the probe on firmware.image_signed so unsigned uploads go straight
from verify to reboot, as before #27237. Signature verification still
runs for signed images.
The Micro-XRCE-DDS-Client-v3 submodule was added without a corresponding
prune entry, so 'make format'/'make check_format' would reformat its
vendored sources. Add it to the exclusion list alongside the existing
Micro-XRCE-DDS-Client entry.
* src/drivers/cdcacm_autostart: Include posix.h for px4_close
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* platforms/nuttx/CMakeLists.txt: Fix linking of nuttx libaries for memalign
This fixes memalign not found in linking step for some boards
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* Add "flock" to macos.sh setup script
"flock" is not standard on macOS, and a dependency was missing from the
macOS setup path.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* Fix clang-tidy errors in Bitset.hpp and in src/lib/matrix
Fix the "bugprone-dynamic-static-initializers" linter errors.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* systemlib/hardfault_log: Fix clang-diagnostics error
Fix for
"[error] clang-diagnostic-error [error]
use of undeclared identifier XCPTCONTEXT_REGS".
XCPTCONTEXT_REGS is defined in nuttx irq.h, so include that.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* uORB: Fix clang-tidy error "bugprone-dynamic-static-initializers"
Fix the clang-tidy error appearing on uORBManager _Instance variable by
adding a getter for the reference to the _Instance and using that instead.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* CI: Add default ubuntu mirrors as fallback
In case of specified aws mirror doesn't have the package idicated by the
metadata, a the default ubuntu mirror as a backup.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
---------
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
* feat(secure_bootloader): add ed25519 key and signing helpers
Scaffolding for PX4 secure-boot firmware signing, split into two
self-contained scripts:
- generate_signing_keys.py: produces <name>.json (private+public hex)
for use by sign_firmware.py and <name>.pub (C-array public key)
for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn.
Refuses to overwrite existing private-key files.
- sign_firmware.py: pads an input .bin to a 4-byte boundary and
appends a 64-byte ed25519 signature, producing a file that drops
directly into the flash slot described by the image TOC.
Optionally appends an R&D certificate binary after the signature.
Replaces the signing path of the old Tools/cryptotools.py that was
removed along with the log-encryption cleanup; the new layout keeps
bootloader-signing tooling separate from log encryption to avoid
confusing the two independent crypto surfaces.
* fix(bootloader): panic if px4_get_secure_random is ever called
sw_crypto's crypto_open() unconditionally references
px4_get_secure_random from its XCHACHA20 path, so even a bootloader
that only performs ed25519 signature verification (and never touches
stream ciphers) pulls in an undefined symbol at link time.
The app build resolves it through nuttx_random.c, which is gated
behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the
NuttX random pool is enabled. That config isn't on in the tiny
bootloader NuttX defconfig, and enabling it would pull in a pile
of kernel code the bootloader doesn't need.
Supply the symbol locally, but make it call up_assert() instead of
returning zeros. Silently handing out predictable bytes would be a
serious security bug if anyone later enables the XCHACHA20 path in
the bootloader without wiring up a real RNG. Aborting makes the
mistake impossible to miss.
* fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check
Today a signed-boot failure is invisible to the uploader: verify_app()
runs inside jump_to_app() after PROTO_BOOT has already rebooted the
chip, so the host sees a successful upload followed by the device
silently staying in the bootloader. There is no protocol-level signal
that the image that was just written is not going to run.
Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run
find_toc() + verify_app(0) *before* the reboot and get a concrete
OK / FAILED / INVALID answer back over the still-open USB connection.
The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built
without secure boot return cmd_bad (INSYNC/INVALID) so an uploader
can tell "I don't know this command" apart from "verification failed".
Two subtleties required care:
1. PROG_MULTI deliberately defers the very first word of the app
image to a RAM variable (first_word) and only commits it to flash
inside PROTO_BOOT, so a partial upload can never become bootable.
But verify_app() reads directly from flash, so if we verified
before committing first_word, even a valid image would always
fail (the first four bytes at APP_LOAD_ADDRESS would still be
0xffffffff). The handler therefore mirrors the first half of the
PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the
deferred first word, then run the crypto check.
2. On failure we deliberately do not try to "undo" the first-word
write — H7 flash programming granularity makes it impossible to
revert in place, and the device was going to end up in the same
reject state at the next boot either way. The improvement is
purely that the uploader sees the failure before REBOOT instead
of after.
Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and
0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which
an AP-compatible uploader might.
ArduPilot also has bootloader secure boot (monocypher ed25519, like
us) but their verification runs at boot time, not upload time — so
neither project currently solves the "upload silently wrote a bad
image" problem. This puts PX4 ahead on that.
* feat(Tools): add --image_signed to mark signed firmware for uploader
px_uploader.py only needs to run signature verification over USB for
images that actually carry a signature — asking the bootloader to
verify an unsigned image would always fail, and the extra round trip
is wasted time for the common unsigned case. It therefore needs a
reliable way to tell the two apart.
We cannot tell by inspecting the bytes: a sign_firmware.py output is
just the raw .bin with 64 bytes of ed25519 signature glued on the
end, indistinguishable in content from an unsigned image of the same
padded length. The natural place to put the flag is the .px4 JSON
envelope, which already carries board_id / version / summary / etc.
Add --image_signed to px_mkfw.py, which sets "image_signed": true
in the emitted JSON. The flag has no effect on what bytes actually
end up on the device — it just tells the uploader "this blob has a
signature, please verify it before booting".
* feat(Tools): verify firmware signature before reboot
After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to
the bootloader to check the ed25519 signature over the freshly
flashed image *before* sending REBOOT. This way a signature failure
is reported as a clean error from the uploader script, instead of a
silent "device stays in bootloader after reboot" that leaves the user
guessing.
The uploader always probes VERIFY_SIG. The bootloader is the source
of truth for whether secure boot is enabled:
- INSYNC/OK -> verification passed, proceed to REBOOT
- INSYNC/FAILED -> raise; "Signature does not verify against any
trusted key" if the firmware claims to be signed,
"Secure bootloader rejected an unsigned image"
otherwise (= helpful guidance for the common
misconfiguration of uploading default firmware
to a secureboot bootloader)
- INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed
unless the firmware metadata says image_signed,
in which case raise.
- recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed.
Surfaces a "Verifying image signature... passed" line on the upload
status path when the firmware is marked signed, so users get a clear
positive signal that the secure-boot pipeline ran end-to-end.
Also drop the redundant logger.error in the upload() loop, which was
duplicating the error message printed by the top-level handler in
main() for every UploadError path (not specific to verify_signature,
but only became obvious once these clean error messages started
firing in normal usage).
* fix(cmake): fix .px4board variant resolution to require exact match
px4_config.cmake matched the requested CONFIG against each candidate
.px4board with `MATCHES`, which is a regex partial match. For a
config like `px4_fmu-v6x_bootloader_secureboot`, the iteration over
.px4board files (alphabetical glob order) would match
`bootloader.px4board` first — because "px4_fmu-v6x_bootloader" is a
prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently
selecting the wrong board config.
Use `STREQUAL` instead so each candidate has to match the full
requested CONFIG. Existing single-label cases (e.g. exact match on
`px4_fmu-v2_default` or `px4_fmu-v2`) are unaffected because they
were already exact in practice; this just plugs the prefix-match
hole that any future `<label>_<suffix>` variant would trip over.
* fix(nuttx): support bootloader_<variant> labels
Boards can ship bootloader variants beyond the default `bootloader`
label — e.g. a `bootloader_secureboot` that adds crypto + keystore
Kconfig on top of the same source tree. Two pieces of build glue
were hardcoded to the exact label `bootloader` and need to relax to
match any `bootloader_*` label:
1. platforms/nuttx/CMakeLists.txt picked the bootloader linker
script and bootloader-specific library list only when the label
was exactly `bootloader`. Any other label (including
`bootloader_secureboot`) silently fell through to the app build,
producing nonsensical link flags. Match `^bootloader` instead,
and explicitly set SCRIPT_PREFIX to `bootloader_` so all
bootloader variants share the single existing linker script
regardless of their full label.
2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config
subdirectory by exact label match, falling back to `nsh` when no
matching directory exists. For `bootloader_secureboot` that fell
through to `nsh`, dragging in a full app-style NuttX with cromfs,
networking, and the full heap subsystem — a 128 KB bootloader
sector overflowed by ~50 KB. Add an intermediate fallback: if the
label starts with `bootloader` and a `bootloader/` subdir exists,
use that instead of `nsh`.
Both changes are backward-compatible: existing single-label
`bootloader` builds take exactly the same path as before. They only
gain the ability for boards to add `bootloader_<suffix>.px4board`
files without duplicating bootloader build wiring.
* feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT
Add a Kconfig pair that boards can opt into:
CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519
CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key
(default: Tools/test_keys/test_keys.json)
When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py
step between the unsigned .bin and px_mkfw.py, and passes --image_signed
so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG
step. The unsigned .bin is still produced alongside the .px4, so users
can sign with their own key out-of-tree if they prefer.
A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path
at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn
in stub_keystore. This makes release builds practical:
BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot
Relative paths in the Kconfig are resolved against the repo root (not
the build directory) so the same value works regardless of where the
build runs from.
Default builds are byte-identical to before; the new code path is gated
on CONFIG_BOARD_SECUREBOOT being set.
* feat(boards): add secureboot demo variant + docs
Two coordinated build variants demonstrate end-to-end secure boot
on px4_fmu-v6x without touching the default builds:
px4_fmu-v6x_secureboot -- the app, with TOC + signing
px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader
App side (secureboot.px4board):
- Selects nuttx-config/scripts/secureboot-script.ld via
CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default
layout plus a fixed 0x800 reservation past the vector table for
the image TOC, and an empty .signature section at end-of-FLASH
so sign_firmware.py knows where the appended ed25519 signature
will land.
- Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the
layout used elsewhere in the tree) into drivers_board, gated on
PX4_BOARD_LABEL == secureboot so the default build still
produces the existing layout.
- Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the
image with the upstream test key by default.
Bootloader side (bootloader_secureboot.px4board):
- Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE,
which links monocypher and the stub keystore into the bootloader.
- Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired
with the test_keys.json the app variant signs with.
- hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM
(CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO,
so they only activate in this variant.
Together the two variants implement the workflow:
make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once
make px4_fmu-v6x_secureboot upload # signs with test key, verifies
Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections
stripping the unused libtomcrypt code; nothing in the bootloader
binary depends on monocypher beyond the ed25519 verifier.
Replace the bundled test key for production with
Tools/secure_bootloader/generate_signing_keys.py output and update
both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) —
see docs/en/advanced_config/bootloader_secure_boot.md.
* fix(boards): cap H7 bootloader linker scripts at 128 KB
Roughly half of the H7 boards in tree had `LENGTH = 2048K` for the
bootloader sector in their bootloader_script.ld, even though the
matching app linker script places APP_LOAD_ADDRESS at 0x08020000 —
i.e. the bootloader actually only owns the first 128 KB sector.
The 2048K constraint is wrong: it lets a bootloader that grew past
the 128 KB sector silently overflow into the app sector at link
time and corrupt the start of the app on flash. The linker should
fail the build instead.
The current default bootloader is ~46 KB, well under 128 KB on every
affected board, so this change is a no-op for default builds. It
just plugs a footgun for anyone adding bootloader features (secure
boot, extra UI, network boot, ...) that would have otherwise
silently grown into the app's flash range.
Boards fixed:
3dr-style H7 reference boards: cubepilot/cubeorange,
cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7
vendor variants: corvon/743v1, cuav/nora, cuav/x7pro,
gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1,
matek/h743, matek/h743-mini, matek/h743-slim,
micoair/h743, micoair/h743-aio, micoair/h743-lite,
micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2
Boards already correct (LENGTH = 128K) are unchanged.
* fix(ci): add pynacl to Python requirements
Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519
signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT
calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot).
Without pynacl in the dev requirements, those builds fail in CI and
fresh dev setups.
* docs(update): Subedit
* docs(update): Fix example error I made
* fix(docs): document BOOT and SIG1 regions
* fix(platforms): style fix
* fix(ci): workaround to get pip dependency
* fix(ci): fall back to plain pip on older build containers
The voxl2 build image ships a pip that predates --break-system-packages
(added in pip 23.0.1), so the install step blew up with "no such option".
Modern containers enforce PEP 668 and need the flag; older ones don't
support it but also don't enforce PEP 668, so plain pip works there.
Try the modern flag first, fall back if pip rejects it.
Signed-off-by: Julian Oes <julian@oes.ch>
* fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build
cmake-build was passing the full build-dir name (including any
BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which
the board-lookup in cmake/px4_config.cmake then tried to match
against <vendor>_<model>_<label> .px4board files. That used to work
by accident because px4_config.cmake matched with regex MATCHES, but
since the switch to STREQUAL (needed to disambiguate
bootloader_secureboot from bootloader) the suffixed CONFIG no longer
matches anything and LABEL ends up empty, tripping a CMake error in
kconfig.cmake.
Pass the bare CONFIG and keep the suffix only on the build dir so
both concerns are independent.
Signed-off-by: Julian Oes <julian@oes.ch>
---------
Signed-off-by: Julian Oes <julian@oes.ch>
Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
* docs(tools): uORB parser: Comma separate multiple enums
* docs(tools): uORB parser: Backlink from enum to field
* docs(tools): uORB parser: index.md section for historic versions
* docs(tools): uORB parser: summary fragment to ease updates
After sending reboot-to-bootloader, the PX4 USB CDC node briefly
disappears while the bootloader re-enumerates. Reopening the serial
port can land on a half-broken descriptor and the next tcdrain()
raises termios.error (5, 'Input/output error'). That bare OSError
escaped every retry layer and crashed the uploader, even though a
manual re-run would succeed once enumeration settled.
Convert OSError/SerialException from flush() and reset_buffers() into
the module's ConnectionError, matching how send()/recv() already
behave, and let the identify retry loops in _try_identify also catch
ConnectionError so a single transient I/O hiccup doesn't abort the
upload.
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Place firmware .bin files at the SD card root or staging directory
(/fs/microsd/ufw_staging/); on boot the UAVCAN server migrates them
to /fs/microsd/ufw/ and updates FW.db, then flashes any connected
node whose firmware version mismatches.
- Add firmware migration from SD root and staging dir into /fs/microsd/ufw/
- Maintain FW.db flat-file database mapping board IDs to original filenames
- Use cache-aligned DMA-safe read/write buffers (required on STM32H7)
- Add Tools/auterion/remote_update_fmu.sh for SSH-based FMU+canio updates
* fix(ci): wipe NuttX submodule state between boards in build_all_runner
NuttX .o and lib*.a live in the shared submodule trees under
platforms/nuttx/NuttX/{nuttx,apps}, not in per-board build/<board>/.
NuttX's recursive make doesn't treat PX4's per-board defconfig changes
as a reason to recompile, so consecutive board builds in one workspace
were linking stale objects from an earlier board (e.g. stm32_spi.o from
fmu-v2 linked into fmu-v4pro, which doesn't enable SPI4).
Run git clean -dXf on both NuttX submodules between iterations to drop
gitignored build state. This mirrors what make clean already does for
submodules and preserves the incremental-build wins for single-board
use.
* fix(cmake): isolate kernel mm/libc objects with BINDIR=kbin
mm and libs/libc compile the same sources for both the kernel and user
passes in protected builds. Without separate output dirs the kernel
objects clobber bin/*.o and the user-mode libmm.a/libc.a end up pulling
in kernel-only symbols (nxsem_wait, g_current_regs, nx_read, nx_write,
g_mmheap, ...) at link time. Matches NuttX's own tools/LibTargets.mk.
* chore(boards): copy ark/fmu-v6x to ark/fmu-v6s
Verbatim copy of ark/fmu-v6x board support to ark/fmu-v6s to
establish a baseline. Functional changes will follow in the next commit.
* feat(boards): add ark/fmu-v6s board support
Low-cost variant of ARK V6X with:
- STM32H743IIK6 MCU (no hardware crypto)
- Single IIM-42653 IMU on SPI1 (SPI2/SPI3 removed)
- IIS2MDC magnetometer on I2C4
- BMP390 barometer on I2C4
- Single sensor power rail
Board ID 61, USB PID 0x003C.
* feat(px4_uploader): add ARK FMU v6s USB ID to the uploader
* refactor: rename SENS_IMU_TEMP to HEATER1_TEMP in rc.board_defaults
* refactor: remove unused ADC channel definitions in board_config.h
* refactor: update ADC channel definitions and remove unused sensor power control
* arkv6s sensor roations
* Add support for Murata SCH16T IMU in default.px4board configuration
* Update bootloader binary for FMU v6s
* Update boards/ark/fmu-v6s/src/hw_config.h
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Update boards/ark/fmu-v6s/src/hw_config.h
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(ark/fmu-v6s): enable CONFIG_CRYPTO for encrypted_logs build
CONFIG_CRYPTO_RANDOM_POOL was set without its parent CONFIG_CRYPTO,
so it was silently dropped and px4_get_secure_random was compiled out,
breaking the ark_fmu-v6s_encrypted_logs link.
---------
Co-authored-by: alexklimaj <alex@arkelectron.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The bootloader boot-delay feature has been mechanically broken on
every modern FMU board since the STM32F7/H7 transition. It has three
independent bugs that prevent it from ever working:
1. Offset mismatch: BOOT_DELAY_ADDRESS is hardcoded to 0x1a0, but the
NuttX vector table is 504 B (F76x) to 664 B (H743) long. The
linker places _bootdelay_signature at ALIGN(32) past end of
vectors (e.g. 0x2a0 on CubeOrange), never at 0x1a0. The bootloader
reads random exception_common pointers in place of the magic and
never matches BOOT_DELAY_SIGNATURE1/2. Verified on CubeOrange with
objdump of cubepilot_cubeorange_default.elf.
2. Flash cache never flushes: fc_write() stores arbitrary writes in
cache line 1 and only flushes on a very specific condition tied
to the sequential firmware upload flow. A standalone write during
PROTO_SET_DELAY is cached forever. fc_read() then returns the
cached value, so the post-write verify lies and the bootloader
reports success. Nothing ever reaches flash.
3. H7 write granularity: the STM32H7 flash controller requires a
full 32-byte program cycle per write. Single 32-bit writes from
flash_func_write_word() would not be accepted by the controller
even if they reached it.
The feature has been silently dead on every H7/F7 FMU board for
years and no one noticed, which is strong evidence nothing actually
depends on it. Rather than fix it (which would mean rewriting
PROTO_SET_DELAY, the flash cache path, and the H7 flash programming
path), remove it.
Changes:
- bl.c: PROTO_SET_DELAY case now immediately NACKs (goto cmd_bad)
so clients that still send the command get a clear rejection
instead of the previous silent fake-success. The opcode stays in
the protocol enum for backwards compatibility.
- bl.h: drop BOOT_DELAY_SIGNATURE1/2 and BOOT_DELAY_MAX.
- stm/stm32_common/main.c, nxp/imxrt_common/main.c: drop the
startup boot-delay sig check block.
- image_toc.c: decouple find_toc() from BOOT_DELAY_ADDRESS.
BOARD_IMAGE_TOC_OFFSET is now the required define when
BOOTLOADER_USE_TOC is enabled. The body is wrapped in #ifdef
BOOTLOADER_USE_TOC and falls back to a stub returning false when
the TOC is not in use (no upstream board currently enables it).
- Linker scripts: strip EXTERN(_bootdelay_signature) and the
FILL/. += 8 block from all 142 affected .ld files across boards/.
- hw_config.h: strip the #define BOOT_DELAY_ADDRESS and its comment
block entry from all 48 affected boards.
- Tools/px4_uploader.py, Tools/teensy_uploader.py: remove --boot-delay,
set_boot_delay(), and SET_BOOT_DELAY client-side counterpart.
Smoke-built on cubepilot_cubeorange_default and
cubepilot_cubeorange_bootloader; no link errors, no unresolved
symbols, flash usage unchanged.
Tested:
- New BL, new FW
- Old BL, old FW
- Old BL, new FW
- New BL, old FW
These fire when clang-tidy analyzes a header whose including TU is not
in the active compile_commands.json (e.g. board-specific NuttX headers
against the SITL clang build), producing spurious line-anchored review
comments on every new-board PR. Real missing includes are caught by the
build_all_targets matrix, which fails the build loudly. Filter the
class of finding at the producer so it never reaches the poster.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The px4-gazebo .deb already declares OpenCV and gstreamer core library
deps via dpkg-shlibdeps, but Dockerfile.gazebo uses dpkg -x which
bypasses resolution. Switch to apt install ./px4-gazebo_*.deb so Depends
are resolved automatically.
Add the 5 gstreamer plugin packages (plugins-base/good/bad/ugly/libav)
to CPACK_DEBIAN_PACKAGE_DEPENDS since they're loaded at runtime via
gst_element_factory_make() and cannot be detected by shlibdeps.
Apply the same apt-install pattern to Dockerfile.sih so both images
build consistently.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
The px4-sim / px4-sim-gazebo Homebrew meta-formulae can no longer
pull their Gazebo dependency chain because Homebrew 4.5+ stopped
auto-resolving cross-tap deps. PX4/homebrew-px4#104 already
deprecated px4-dev into a no-op; #111 does the same for the sim
formulae. This PR is the PX4-side counterpart: move the sim install
into Tools/setup/macos.sh with an explicit package list and tap
registration, mirroring the pattern already used for the toolchain
block. Adds xquartz install on --sim-tools.
Beyond install, three runtime and configure gaps kept make px4_sitl
gz_x500 from working on a clean macOS:
- gz-gui8 (pulled in by gz-sim8) links against Qt5, but Homebrew's
qt@5 is keg-only so CMake cannot find it. Add a POSIX-scoped hint
in platforms/posix/cmake/px4_impl_os.cmake that resolves
brew --prefix qt@5 and appends it to CMAKE_PREFIX_PATH. No-ops on
non-APPLE builds and respects a user-set Qt5_DIR.
- On macOS, dyld does not search /opt/homebrew/lib by default.
gobject-introspection typelibs reference libs by bare basename,
causing gst-plugin-scanner to fail to load plugins and adding
~90s of timeout to Gazebo's cold start. Set
DYLD_FALLBACK_LIBRARY_PATH to the Homebrew prefix lib dir in
gz_env.sh so the bridge launch inherits it. Darwin-scoped, no
effect on Linux or CI.
- configure_file on gz_env.sh.in now uses @ONLY so shell ${VAR}
references pass through untouched.
Verified locally on macOS 26.4 / arm64 / Homebrew 5.1.7: configure
clean, 1119/1119 targets compile and link, vehicle spawns in
Gazebo Harmonic 8.11.0 with a single "Waiting for Gazebo world"
wait (was ~18 before the dyld fix).
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
* feat(astyle): add make format_changed for diff only style fixes
`make format` is pretty slow because it always considers the entire
source tree. For developing on top of a clean state, considering only
files that differ from HEAD should be sufficient.
* docs(astyle): document new format_changed target
Homebrew 4.5 (April 2026) stopped auto-tapping cross-tap
dependencies declared in formulae, as a security + performance
change. The px4-dev meta-formula pulled in packages from
osx-cross/arm, PX4/px4, and discoteq/discoteq, so 'brew install
px4-dev' now aborts before any real work unless every tap has been
added explicitly. On macos-latest CI runners the chain broke at the
first unreachable dep (discoteq/discoteq/flock) and subsequent make
steps failed with 'ccache: command not found'.
Since Tools/setup/macos.sh is the canonical install path and already
tapped osx-cross/arm and PX4/px4 before calling brew install, the
simplest fix is to inline the package list and call brew install
directly. The px4-dev meta-formula will be kept upstream as a
deprecated no-op so older copies of macos.sh on long-lived branches
and cached Docker images keep working.
The inlined package list is the same set px4-dev depended on, minus
the dead-weight flock dependency that hadn't been invoked in the PX4
build since the NuttX 9.1.x era. See the accompanying PX4/homebrew-px4
PR for formula changes.
Docs updated to match: docs/en/dev_setup/dev_env_mac.md no longer
names the px4-dev formula, describes the package list directly.
Verified locally on macOS ARM64:
- ./Tools/setup/macos.sh runs to completion with both taps and all 13
packages resolving correctly
- make distclean && make px4_fmu-v6x_default builds successfully
(1250/1250 ninja steps, 1930096 B FLASH used)
Signed-off-by: Ramon Roche <mrpollo@gmail.com>