Commit Graph
100 Commits
Author SHA1 Message Date
Peter Barker 818be63b54 AP_ROMFS: don't read past a shorter name when skipping duplicate directories
dir_list() compares an entry's leading directory with the previous
entry's using memcmp() over the directory's length, which reads past the
end of the previous name when that is shorter. strncmp() stops at its
end.
2026-09-24 18:35:09 +10:00
Peter Barker 7296d28042 autotest: check FTP lists and reads @ROMFS
Nothing listed @ROMFS. Walk it as a GCS browsing it would, and check every
file named in the build's embedded header is found, at its decompressed
size, with nothing extra and no directory listed twice. Then read
vehicleinfo.json out of it, which is stored compressed and takes many
reads, and check it matches the file it was built from.
2026-09-24 18:35:09 +10:00
Peter Barker 2778384644 waf: embed ROMFS entries with names too long for a directory entry
SITL's ROMFS gains a file and a directory, each with a 300 character name,
so the tests can check listing them is safe: a directory entry's d_name
is 255 bytes on ChibiOS and 256 with glibc, so neither name fits. They go
under autotest_fixtures, where autotest's fixtures are kept apart from
anything a user embeds.
2026-09-24 18:35:09 +10:00
Peter Barker 251092473a Tools: shorten column names in global size summary table
Use Periph, tracker and iofw in the header to keep the table narrow.
2026-09-24 13:35:21 +10:00
Peter Barker 51772d0971 autotest: detect MAVFTP fetch completion by MAVProxy's success message
fetch_file_via_ftp() polled 'ftp status' for 'No transfer in progress'
and took that as completion, within a timeout measured in simulated
time.  Both are wrong:

 - the loop is paced by MAVProxy and pexpect, not the simulation.  At
   full speedup a single one-second expect consumes the whole
   twenty-second sim-time budget, so a status poll which lands
   mid-transfer fails the fetch about a second after it began, even
   though the file arrived:

     Wrote 7403 bytes to /tmp/tmptcsw8tm2 in 0.02s 391.1kByte/s
     Timed out looking for No transfer in progress
     Exception caught: expected complete transfer

 - 'No transfer in progress' is also true before the transfer starts,
   and after one is aborted, so it can yield an empty or truncated
   file.  PerfInfo has failed both ways:

     Expected TasksV2 as first line first not ()
     Expected EFI last not (AP_Generator::update ...)

Expect MAVProxy's 'Wrote N bytes to' message instead, which is printed
only once the whole file has been written, with a wall-clock timeout,
and retry the fetch a couple of times if it does not arrive.
2026-09-24 11:24:26 +10:00
Peter BarkerandClaude Opus 5 1a88f20be1 autotest: remove the script we installed, not the one we installed from
install_script() honours install_name when choosing the destination, but
install_applet_script_context() recorded the source name for removal, so
a script installed under a different name was never cleaned up when the
context went away.

AerobaticsScripting installs Aerobatics/FixedWing/Schedules/AirShow.txt
as trick72.txt: context pop then tried to unlink scripts/AirShow.txt,
which had never existed, and left scripts/trick72.txt behind after every
run.  The scripting engine itself never loads that leftover - it takes
only names ending in .lua - but plane_aerobatics.lua searches scripts/
for trick<n>.txt, so a later run reads the stale copy and would still
pass even if the install had broken.

install_script_module_context() and install_driver_script_context()
already resolve install_name this way; do the same here, and spell the
parameter out as they do rather than taking it through **kwargs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 08:05:35 +10:00
Peter Barker 25dc1c4640 Tools: run_coverage.py: cope with lcov 2.x fatal error classes
lcov 2.x, as shipped in the Ubuntu 24.04 CI containers, promotes two
conditions the weekly coverage run always hits from warnings to fatal
errors:

 - "mismatched end line": two functions starting on the same source
   line with different end lines.  Every gtest TEST() body trips this,
   as the macro also defines the fixture constructor and destructor on
   the TEST() line, so both lcov --capture invocations abort.
 - "unused": a --remove pattern which matched nothing; ".waf*" never
   matches, so the pattern-removal step aborts.

Pass --ignore-errors for those classes on the affected invocations.
lcov 1.x rejects unknown error classes, so the arguments are only
emitted when lcov reports version 2 or later.
2026-09-23 08:37:53 +10:00
Peter BarkerandPierre Kancir b3c52b2fcb waf: apply coverage flags after the configure checks have run
The coverage flags were added in configure_env, so every probe program
built by cfg.check() was compiled with -fprofile-arcs and linked with
-lgcov.  On boards which also link with -Wl,--wrap,malloc (SITL, Linux,
QURT) libgcov's malloc call is rewritten to __wrap_malloc, which the
probe does not define, so the probe fails to link and the feature under
test is silently recorded as absent.  Under --coverage every header
check ("endian.h", "byteswap.h", the cmath checks, memrchr) reported
"not found"; HAVE_BYTESWAP_H was never defined and the fallback in
AP_Common/missing/byteswap.h was compiled instead.  That fallback
collides with glibc's own __bswap_16/32/64 as soon as a translation
unit also includes netinet/in.h, which broke build.unit_tests in the
weekly coverage workflow.

Move the flags into Board.configure_coverage() and call it from the
top-level configure once the checks are done, so the probes are never
instrumented and the coverage configuration produces the same
ap_config.h as a normal one.

Co-authored-by: Pierre Kancir <pierre.kancir.emn@gmail.com>
2026-09-23 08:37:53 +10:00
Peter BarkerandClaude Opus 5 a64bad1a0d AP_HAL_SITL: only enable AP_Airspeed on SITL periphs with airspeed support
Mirror the defaults_periph.h change for SITL periph builds: those which
do not set AP_PERIPH_AIRSPEED_ENABLED never instantiate an AP_Airspeed
object, so should not compile the library in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 14:16:42 +10:00
Peter Barker 1ca11f1b19 AP_Module: instantiate AP_Airspeed in ModuleTest example
AP::airspeed() now returns a reference, so code reached from this
example which consults airspeed would dereference a null singleton if no
AP_Airspeed object exists.
2026-09-22 14:16:42 +10:00
Peter Barker 3be2989526 APM_Control: instantiate AP_Airspeed in AP_FW_Controller_test example
AP::airspeed() now returns a reference, so code reached from this
example which consults airspeed would dereference a null singleton if no
AP_Airspeed object exists.
2026-09-22 14:16:42 +10:00
Peter Barker fa1d3f9a78 AP_Baro: instantiate AP_Airspeed in BARO_generic example
AP::airspeed() now returns a reference, so code reached from this
example which consults airspeed would dereference a null singleton if no
AP_Airspeed object exists.
2026-09-22 14:16:42 +10:00
Peter Barker 2479db714b RC_Channel: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker ee61cb3c41 GCS_MAVLink: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker e7a0c0ad89 AP_WindVane: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 155b5b0533 AP_RCTelemetry: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker fdfa57e6e7 AP_OSD: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 3ffea9ba40 AP_MSP: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 041527b987 AP_LTM_Telem: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 8097a2295e AP_IBus_Telem: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 54ceed5c6c AP_Hott_Telem: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 14dc9fd3ef AP_Frsky_Telem: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 50ff07c8e5 AP_ExternalAHRS: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 7e95431f4f AP_DAL: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 1d7b60d83e AP_Baro: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 8dfedacbd5 AP_Arming: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker cf6c2c09b6 AP_AHRS: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker f9a813fdfd ArduPlane: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker e50237a549 AP_Airspeed: return a reference from AP::airspeed()
Every firmware which compiles airspeed support in also instantiates an
AP_Airspeed object, so the singleton is never null.  Returning a
reference rather than a pointer says so, and lets the nullptr checks at
each call site go away.
2026-09-22 14:16:42 +10:00
Peter Barker 51b1948755 AP_HAL_ChibiOS: only enable AP_Airspeed on periphs with airspeed support
AP_Periph only instantiates an AP_Airspeed object when
AP_PERIPH_AIRSPEED_ENABLED is set, but AP_AIRSPEED_ENABLED defaulted to
1 regardless, leaving the singleton null on other periph builds.  Tie
the two together as is already done for other sensor libraries.
2026-09-22 14:16:42 +10:00
Peter Barker 9ff029f339 .github: pre-build the AP_Periph firmware frame tests build
DroneCANCompass and CircuitStatusScript build sitl_periph_universal
inside the test, which master's ccache did not hold.  Pre-build it with
the options those jobs use so the in-test builds are cache hits, and
add --num-aux-imus=2 to the PPPPeriph pre-builds now that the frame
rebuild uses the Plane jobs' options.
2026-09-22 14:15:25 +10:00
Peter Barker f4d9d491e9 autotest: rebuild frame binaries with the suite's build options
restart_SITL_frame() called build_SITL_frame() with none of the options
the suite was built with, so the frame binaries were configured without
--debug, --num-aux-imus and the rest.  The binary under test then no
longer matched the suite's configuration, and CI - whose ccache holds
--debug objects - rebuilt both firmwares from scratch inside the test:

  DroneCANCompass      sitl 8m19s + sitl_periph_universal 3m51s of 743s
  CircuitStatusScript  sitl 5m51s + sitl_periph_universal 2m43s of 520s

It also left build/sitl configured without --debug for later tests.

Pass the suite's build options through, as the Replay tool build
already does.  PPPPeriph no longer needs to ask for --debug itself.
2026-09-22 14:15:25 +10:00
Peter Barker 8f21583d17 autotest: seed the packet loss in MAVFTPGapReadMAVProxy
Unseeded, MAVProxy draws the lost packets from fresh entropy on every run,
so a failure could not be reproduced. A fixed seed loses the same packets
each time; it still leaves gaps to fill.
2026-09-22 11:10:46 +10:00
Peter Barker fb21a79dee autotest: widen what the FTP listing tests ask for
The listing tests only ever listed a directory they had just made, so the
paths they used were all of one shape. The bug where listing the root
dropped every file lived through all of them because no test named the
root, which is the first thing a file browser asks for.

Cover the shapes a client actually sends: a directory with nothing in it,
and "." for the directory the vehicle was started in.

The long-name test also only listed without times, where the boundary of
what fits a packet sits eleven bytes further out. Run it both ways, with
names either side of the boundary a listing with times has, so that
dropping an entry which no longer fits still cannot end the listing.
2026-09-22 11:10:46 +10:00
Peter Barker f02295ae6e autotest: run the FTP listing tests MAVProxy has caught up with
These three were skipped pending MAVProxy fixes: continuing a directory
listing from the listing's own state rather than by mutating the last
operation sent, and taking a listing entry's size from the end of the
entry. MAVProxy master now does both, so rather than skipping them
outright they ask MAVProxy whether it can do this and return early if it
cannot.
2026-09-22 11:10:46 +10:00
Peter Barker 06559fb9df autotest: check the lossy FTP listing test lists every entry
The test set 50% receive loss and then waited only for "Total size",
which a listing that gave up part-way through would still print. Wait for
the total the files actually add up to instead.

Give every file a different size while doing so: with all of them the same
the total is just a count, so a listing which lost one page and repeated
another still reached it.
2026-09-22 11:10:46 +10:00
Peter Barker 13b6dc0887 autotest: cover MAVProxy's side of FTP listing with times
MAVFTPListDirectoryWithTimeMAVProxy checks times are asked for by
default and rendered in local time, and that "ftp set list_time 0"
turns them off again. MAVFTPListDirectoryUnknownTimeMAVProxy checks a
file whose time the autopilot does not know shows as "-" rather than as
a date; its directory holds one file, because a listing is printed in
readdir order and an expect for one entry cannot sit behind another.

MAVFTPListDirectoryFallbackMAVProxy makes the timestamped replies
disappear with the module's own pkt_loss_rx and requires the plain
listing to complete once the loss is lifted - the fallback is the whole
point of the new opcode and nothing else exercises it.
MAVFTPListDirectoryLossyRetry drops half the replies and requires the
listing to finish, as it has no retransmit of its own.

MAVFTPListDirectoryWithTimeMAVProxyTabInName is the timestamped
counterpart of the existing tab test, which takes the size and the time
from the end of the entry rather than the size from the front.

That existing test now asks for a plain listing explicitly: against a
MAVProxy which knows the opcode it would otherwise get a time it is not
expecting.

All are skipped, as they need a MAVProxy which is not released yet.
2026-09-22 11:10:46 +10:00
Peter Barker fb032423eb autotest: check @MAV_LOG against what the FTP spec asks of it
The spec says a virtual directory is named with an @ prefix, that the
recipient maps it to the underlying filesystem, and that a path which is
not there is NAKed FileNotFound. Check each of those: the alias lists what
the log directory holds, a path below it resolves both with and without
the trailing slash the spec's own example carries, an unknown path below
it is NAKed FileNotFound, and a file read through the alias gives back
what was written.
2026-09-22 11:10:46 +10:00
Peter Barker d437708812 Tools: add @MAV_LOG build option
@MAV_LOG has no class of its own to find in the symbol table, so it is
detected by its prefix string, which only the backend table row puts in the
binary. That row is also only built where logs go to a filesystem, so the
option depends on Logging.
2026-09-22 11:10:46 +10:00
Peter Barker bc4a6f05a6 AP_Filesystem: add the @MAV_LOG virtual directory
MAVFTP defines @MAV_LOG as the flight-stack-independent location for log
files, so that a GCS can find them without being told where a particular
board keeps them. QGroundControl asks for it before anything else, and
falls back to guessing per-firmware paths when it is not there.

It is an alias rather than a filesystem of its own: the backend table
gains a root, and where a row carries one the resolver rewrites a path
under that prefix to sit under that directory before handing it to the
filesystem which serves it. @MAV_LOG points at the local filesystem, under
whatever directory this board logs to, following a custom log directory
the same way AP_Logger_File does.

The rewritten path has to hold the root as well as the path, so the buffer
is sized for the longest path an FTP listing stats - the longest path a
request can carry, a separator and a 255 byte name - underneath the longest
log directory a board has, and a static_assert holds boards to that. A
path too long to rewrite is refused with ENAMETOOLONG before any filesystem
sees it, rather than being truncated into the name of some other file.

That buffer is not on the stack, where every path-based call would pay for
it. It is allocated the first time an alias is used and kept, and a
semaphore is held around each backend call which uses it. rename, the one
call with two paths alive at once, allocates a second buffer for its new
path and frees it afterwards. Paths which are not aliases take neither the
semaphore nor a buffer.

An alias can't sit on LittleFS for now, and @MAV_LOG is not built where
LittleFS is the local filesystem; forcing it on is a build error. LittleFS
holds its lock from opendir() to closedir(), so the semaphore, held across
each call, would be released before that lock, which ChibiOS mutexes do not
allow, and a thread listing an alias directory would wait for the semaphore
while holding the lock another thread holding the semaphore could be
waiting for.

rename now compares the filesystems which serve its two paths rather than
their table rows, since an alias shares its filesystem with other paths,
and sets EXDEV when they differ.

A prefix now has to be the whole of a path's first component, so that
"@MAV_LOG_backup" is not served as "_backup" under the log directory. This
is not particular to the alias: "@SYSfoo" used to be served by @SYS as
"foo", and is now the local file of that name. Nothing in the tree relied
on the old behaviour.

@MAV_LOG, and the alias support with it, is only built where the logs go
to a filesystem at all.
2026-09-22 11:10:46 +10:00
Peter Barker 645c39f65b GCS_MAVLink: correct the note on the hardcoded ListDirectoryWithTime opcode
The opcode landed upstream in mavlink/mavlink#2491, so what keeps the
value hardcoded is the bundled definitions rather than anything upstream.
2026-09-22 11:10:46 +10:00
Peter Barker d21c0babed autotest: check a timed FTP listing sends a skip entry for a tab
A name containing a tab must come back from ListDirectoryWithTime as a bare
skip entry, with the names around it still listed, while a plain listing
still sends it as it is.
2026-09-22 11:10:46 +10:00
Peter Barker 0848b31ea1 GCS_MAVLink: send a skip entry for a name with a tab in a timed listing
A tab separates the fields of a listing entry, so a name containing one
cannot be represented. The MAVFTP spec (mavlink-devguide#738) has such an
entry sent as a skip entry, which keeps entry offsets consistent, and
ListDirectoryWithTime follows List Directory in this. Plain listings are
left sending the name as they always have.
2026-09-22 11:10:46 +10:00
Peter Barker 8ad4a29a6f autotest: check FTP directory entries carry a size and time
A listing with times gives a directory the same three fields as a file,
so the listing helper now picks directory entries apart the same way and
the test checks the subdirectory's size and time. The subdirectory gets a
modification time of its own so that an entry carrying some other entry's
time would be caught.
2026-09-22 11:10:46 +10:00
Peter Barker 42277bd175 GCS_MAVLink: report a size and time for directories in FTP listings
The listing format gives every entry a size, and ListDirectoryWithTime
gives every entry a time as well, with the type character the only thing
distinguishing a directory from a file. We emitted a bare "D<name>" for a
directory instead, so a client parsing the documented three fields found
only one.

A directory has no meaningful size, so it is reported as zero. Listing
with times now has to stat a directory as well; one which cannot be
stat'ed is still listed, with its time reported as unknown.

Plain ListDirectory is unchanged: it still emits the bare "D<name>" it
always has, so no existing client sees a different directory entry.

MAVSDK's server already sends these fields and its client parses them.
QGroundControl assumed a directory entry was a bare name; a fix for that
is in hand.
2026-09-22 11:10:46 +10:00
Peter Barker 3e28e00457 autotest: add a test for FTP ListDirectoryWithTime
Lists a directory of files with known sizes and modification times both
with and without times, paging through the listing by entry count as a
GCS does, and checks the entry format, that directories are still bare
D entries, and that a time the autopilot does not know comes back as
the zero the format defines rather than as the FAT epoch.

The listing helpers learn to ask for times; the directory they build
gets modification times to ask about.
2026-09-22 11:10:46 +10:00
Peter Barker 64ef7e1a1e GCS_MAVLink: report an unknown file time as zero in FTP listings
The listing format defines an mtime of zero as "the autopilot does not
know when this file was written", but no filesystem we have ever emits
it. FATFS stamps a file with the FAT epoch, 1980-01-01, when it has no
RTC to ask - and RTC_TYPES defaults to GPS only, so a vehicle which has
not had a fix stamps every file it writes that way. Confirmed on a
ZeroOneX6: every file on the card, across dozens of boots, comes back
as 1980-01-01.

Nothing at or before the FAT epoch is a real modification time, so send
the zero the format defines and let the client say it does not know.

Done here rather than in AP_Filesystem_FATFS::stat(), whose st_mtime
also reaches LOG_ENTRY.time_utc and the scripting stat() binding.
2026-09-22 11:10:46 +10:00
Peter Barker 5c91607e1b autotest: check the exact trim AHRSTrim saves
The previous thresholds only checked the sign and a 2-degree minimum.
On the ground the pilot's total lean is limited to 10 degrees, split
across both axes by the test's diagonal stick, so the saved trim is
fully determined; check it against that value.
2026-09-22 09:30:40 +09:00
Peter Barker 5bec328c81 Copter: tidy comments and indentation of moved AHRS trimming code
Removes the comment claiming save_trim is a method on RC_Channels, moves
the auto-trim description from auto_cancel to auto_run which it
describes, and drops the extra indentation level auto_start and auto_run
carried over from their previous nesting.

Whitespace and comments only.
2026-09-22 09:30:40 +09:00
Peter Barker c892590775 Tools: update AHRS auto-trim feature symbol for its move into Copter
The auto-trim scheduler task moved from RC_Channels_Copter::auto_trim_run
to Copter::AHRSTrimming::auto_run, so extract_features.py was reporting
AP_COPTER_AHRS_AUTO_TRIM_ENABLED as absent from binaries which have it.
2026-09-22 09:30:40 +09:00
Peter Barker abd0106bbc autotest: add a test for instantaneous trim switch option 2026-09-22 09:30:40 +09:00
d2fe1453cf Copter: move AutoTrim support into Copter object
Co-authored-by: Ayush Suri <vtdlduddn3267@gmail.com>
Co-authored-by: codemaster1104 <akshatshrivastava1823@gmail.com>
2026-09-22 09:30:40 +09:00
Peter Barker 98b155533c autotest: let the context remove SDCardWPTest's script
SDCardWPTest installed mission_spiral.lua with the non-context
install_example_script() and removed it with a bare
remove_installed_script() thirty lines later, with no try/finally
between them.  Every wait_text() and set_parameter() in that stretch can
raise, and any of them leaves the script installed: the removal is
simply skipped.

That matters more here than for a leaked trick file, because
mission_spiral.lua ends in .lua - lua_scripts.cpp loads every .lua in
scripts/ - so the leftover is picked up and run by the next test to
start a vehicle with scripting enabled.

The test already pushes a context, and the harness pops any the test
leaves behind when it fails, so install_example_script_context() cleans
up on both paths.  Every other install site in Tools/autotest already
uses the _context form.
2026-09-22 07:21:24 +10:00
Peter Barker 9256cd77c5 .github: raise ccache max_size for the macOS builds
pre-commit / ci (push) Canceled after 0s
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
workflows lint / lint (push) Canceled after 0s
The macOS jobs' working set is 480-560MB, so at ccache.env's 400M default
both evicted objects mid-build - 817 cleanups on sitl, 123 on CubeOrange -
and re-compiled them on the next run. Restoring a cache built from the same
source, they hit 42% (CubeOrange) and 19% (sitl); with the cache large
enough to hold the working set both hit 99.8%.

Add a max-size input to setup-ccache so this is per-job rather than global:
raising it for all jobs would waste the repository's shared 10GB cache
quota on the ~60 jobs that use well under 400M. The two macOS entries grow
by 208MB in total.
2026-09-21 19:25:22 +10:00
Peter Barker 69b3dc83c5 .github: only build copter for the macOS debug build
The macOS workflow built every vehicle twice, once normally and once
with --debug. The second pass doubled build time and, since debug and
non-debug objects don't share ccache entries, overflowed the 400M ccache
limit, so the cache thrashed even when warm.

A single vehicle is enough to check the debug build works on macOS.
Plane, Rover, Sub, Blimp, AntennaTracker and heli no longer get a
--debug (-O0) compile on macOS; each still gets one in its Linux SITL
test workflow.
2026-09-21 19:25:22 +10:00
Peter Barker 0d38ef16d1 Tools: environment_install: add if clauses to avoid churn on add/remove OS
previously adding or removing support for an OS meant changing lines unrelated to that OS.

Add a bit of cruft to the file so that adds/removes are just clean line additions or removal
2026-09-20 14:27:13 -07:00
Peter Barker 665c0deeec SRV_Channel: remove zero_rc_outputs
superseded by prepare_for_reboot(), which its only caller now uses
2026-09-18 00:10:02 +10:00
Peter Barker 26809186b8 AP_Vehicle: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker 94f7e038b0 SRV_Channel: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker 94800d5ae6 AP_HAL_SITL: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker c05eb925b1 AP_HAL_ChibiOS: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker 06c6317934 AP_HAL: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker 985d2f6f6f AP_HAL_Linux: bounds-check channel number in RCOutput write methods
RCOutput_PRU, RCOutput_AioPRU_PB2 and RCOutput_AeroIO wrote into their
channel arrays without checking the channel number; every other Linux
RCOutput backend already does.  On PRU the overrun is particularly
unpleasant as pending[MAX_PWMS] aliases the corked flag, so a write to
channel 12 uncorks the backend and makes the subsequent push() a no-op.

SRV_Channels::output_ch_all() already sweeps 16 channels by default,
so these overruns are reachable today on pxf, erleboard and pocket2.
2026-09-18 00:10:02 +10:00
Peter Barker 8a6d5b2ef7 Sub: prepare for reboot at the HAL rc output level
ensures that the 0s get to the hardware

significantly reduces the race conditions which might allow a thread to write after values are zeroed
2026-09-18 00:10:02 +10:00
Peter Barker 5efdf54920 Revert "hwdef: keep PA15 pulled up in the YJUAV_A6SE_H743 bootloader"
This reverts commit 2f87db990f.

PR #34359 was merged by mistake.  On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default.  The ESC started to enter
throttle calibration.  Back the change out until the hold can be
chosen per output.
2026-09-18 00:04:45 +10:00
Peter Barker 90dcb1680f Revert "bootloaders: rebuild YJUAV_A6SE_H743 to keep PA15 pulled up"
This reverts commit 157d471fe4.

PR #34359 was merged by mistake.  On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default.  The ESC started to enter
throttle calibration.  Back the change out until the hold can be
chosen per output.
2026-09-18 00:04:45 +10:00
Peter Barker e4f836b315 Revert "AP_HAL_ChibiOS: add HOLD_HIGH PWM pins handed to their timer at first output"
This reverts commit 239f5c1f97.

PR #34359 was merged by mistake.  On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default.  The ESC started to enter
throttle calibration.  Back the change out until the hold can be
chosen per output.
2026-09-18 00:04:45 +10:00
Peter Barker 0fae5cc03b Revert "hwdef: hold YJUAV_A6SE_H743 PWM1 high until its first frame"
This reverts commit 67fd60ce26.

PR #34359 was merged by mistake.  On the bench, with an ESC on
YJUAV_A6SE_H743 output 1, the hold presents a continuous high (full
throttle to a PWM ESC) for about 10.5s after every reset, and for as
long as safety is engaged when output 1 is a motor outside
BRD_SAFETY_MASK, which is Copter's default.  The ESC started to enter
throttle calibration.  Back the change out until the hold can be
chosen per output.
2026-09-18 00:04:45 +10:00
Peter Barker 67fd60ce26 hwdef: hold YJUAV_A6SE_H743 PWM1 high until its first frame
PWM1 is on PA15, the JTDI pin, whose reset and power-on pull-up gave the
M1 servo a short pulse on every boot. Declare it HOLD_HIGH so the
application keeps it a pulled-up input until RCOutput's first real
frame, matching the bootloader, which already keeps the pull-up.
2026-09-17 22:56:37 +10:00
Peter Barker 239f5c1f97 AP_HAL_ChibiOS: add HOLD_HIGH PWM pins handed to their timer at first output
The STM32 JTAG pins JTDI (PA15) and NJTRST (PB4) come out of every
reset, and out of power-on, with an internal pull-up enabled, and 84
hwdef directories in the tree route a PWM output through one of them:
61 through PA15, 38 through PB4, 15 through both.  A servo on such an
output sees the line pulled high from then until firmware reconfigures
the pin.  On the H743 that measured 692us to the bootloader's board init
on a warm reset, and 496us and 520us on two cold power-ons.  Each is a
pulse inside the range servos accept, so the servo drives to an endpoint
and holds it through the rest of the boot.  Nothing can shorten that
window, since no code runs during it.

Give hwdef a HOLD_HIGH keyword for PWM pins.  The generator emits such a
pin as a pulled-up input with its timer alternate function preset, and a
HAL_PWM_HOLD_HIGH_MASK of the channels concerned.  It rejects the keyword
on any pin RCOutput will never hand back to a timer: anything other than
a PWM(n) timer output in the main configuration, so also an RC input, the
alarm and an ALT(n) pin.  One predicate decides both that and which pins
get a mask bit, so the two cannot disagree.  The check is made when the
pin is parsed, which covers bootloader builds too.  STM32F1 is rejected
outright, since its pin setup does not honour the keyword at all.

RCOutput keeps each channel an input until the first non-zero value is
pushed to it, in the PWM and DShot output paths, and only then switches
the pin to the timer.  With the bootloader also keeping the pull-up, the
line is high continuously from the reset until the first real frame,
which for a channel outside BRD_SAFETY_MASK means until safety is
disarmed, so the servo sees a high far longer than any valid pulse
rather than a plausible short one followed by seconds of silence.  On
the bench the test servo did not move at all across ten reboots.

The mode switch is an unlocked read-modify-write of the port registers,
and other threads change the modes of other pins on the same port, so
a single write can be lost.  The channel is therefore not marked handed
over until a later output finds the pin already in alternate mode; until
then each output writes the mode again, so a lost write is repaired one
output later rather than leaving the pin an input until reboot.

Several other owners of a pad have to take it explicitly, because none
of them goes through the normal output path:

 - the alarm driver configures a timer and never the pad, and disables
   the group's channels first, so the hold on the alarm's own channel is
   released before that.  Only that channel: no real frame will ever
   arrive for the rest of the group, so a HOLD_HIGH pin among them is
   correctly left held;
 - soft serial saves and restores the pad's mode, so BLHeli passthrough
   hands the pin over when it selects it, or it would save "input" and
   transmit nothing;
 - neopixel and ProfiLED output is chosen at runtime by SERVOx_FUNCTION
   on an ordinary PWM(n) pin and is sent without push_local(), so the
   serial LED path releases its group's pads before driving them;
 - DShot commands such as beeps are sent before arming, when nothing has
   released the pad yet, so the command path releases every channel it
   transmits on;
 - bidirectional DShot, when enabled at runtime, takes the pads of a
   whole group during init, so it clears the pending bit there.  A pin
   merely declared BIDIR keeps its hold; one whose group has bidirectional
   DShot enabled gets no protection.  The hwdef allows HOLD_HIGH and BIDIR
   together deliberately.

Verified under Renode on YJUAV_A6SE_H743 with ArduPlane: the
application's board init leaves PA15 an input, it stays one through
24.8s of init, and the mode write that puts it on TIM2 lands at the same
microsecond as the first non-zero CCR1 write.  With the first mode write
dropped on purpose, the next output found PA15 still an input and wrote
it; unmodified, the second output sees the mode has held and later
outputs no longer read the port.  MatekF405-TE and the IOMCU
firmware still build, and a no-mask board's firmware is byte-identical.
2026-09-17 22:56:37 +10:00
Peter Barker 157d471fe4 bootloaders: rebuild YJUAV_A6SE_H743 to keep PA15 pulled up
Built with Tools/scripts/build_bootloaders.py from the hwdef change that
holds the PWM1/JTDI pin high through the bootloader, so a servo on M1 no
longer receives a 500 to 700us pulse on every reset and power-on.
2026-09-17 22:56:37 +10:00
Peter Barker 2f87db990f hwdef: keep PA15 pulled up in the YJUAV_A6SE_H743 bootloader
PA15 drives PWM1 on this board and is also JTDI, which the STM32H743
brings out of every reset, and out of power-on, with its internal
pull-up enabled. The M1 servo line is therefore held high from then
until the bootloader's board init reconfigured the pin as a floating
input. On logic-analyser captures of the real board that is 692us on a
warm reset, and 496us and 520us on two cold power-ons, one over USB and
one at 12V. Each of those is a pulse inside the range most servos
accept, and it sent the servo to an extreme.

Configure PA15 as an input with pull-up in the bootloader instead, so
the line stays high continuously until the application switches the pin
to its timer, whose idle level is low. The servo then sees one high
lasting the whole bootloader, far outside any valid pulse width, rather
than a plausible command. Verified under Renode with the bootloader
held: PA15 reads input with pull-up while the bootloader owns the pins.
2026-09-17 22:56:37 +10:00
Peter Barker b2b1b3d279 Tools: decode_devid.py: parse device types from the C++ headers
pre-commit / ci (push) Canceled after 0s
test Renode / cubeorangeplus-quadplane (push) Canceled after 0s
test scripts / build (astyle-cleanliness) (push) Canceled after 0s
test scripts / build (check_autotest_options) (push) Canceled after 0s
test scripts / build (logger_metadata) (push) Canceled after 0s
test scripts / build (param-file-validation) (push) Canceled after 0s
test scripts / build (param_parse) (push) Canceled after 0s
test scripts / build (python-cleanliness) (push) Canceled after 0s
test scripts / build (shellcheck) (push) Canceled after 0s
test scripts / build (validate_board_list) (push) Canceled after 0s
Rather than maintaining copies of the bus and device type tables,
decode_devid.py now parses the enums in AP_HAL/Device.h, AP_SerialManager.h
and the compass, IMU, baro and airspeed backend headers using
logger_metadata/enum_parse.py.  A small rename map keeps established
display names (DRONECAN, AK0991x), and the retired LIS2MDL ID, which is
in no enum, is listed explicitly.  Comments on enum entries are shown as
warnings when decoding.

--dump-json and --dump-json5 write the tables, with a format_version
and a content-hash data_version, for tools without a source tree;
--json reads such a file back.  A copy of the script outside an
ArduPilot tree (as synced by MethodicConfigurator) reads devid.json from
its own directory.  The files are published alongside LogMessages.* by
build_log_message_documentation.sh, and CI dumps them in the
logger_metadata step so that header changes which break parsing are
caught.

The tables had drifted from the headers: ACC_LSM9DS1,
INS_ZEROONE_FPGA_SCH16T and INS_ICM56686 were missing, MMC5883 is now
MMC5983, AK8963/BMM150 had trailing spaces, and several names now
follow the headers.
2026-09-16 17:18:56 +10:00
Peter Barker 8392566e2b AP_Compass: document when the mistaken RM3100 device type was used
DEVTYPE_RM3100_2 (0x12) was introduced by dd4cf6ccdd and reverted by
a0cf4e158a; no release firmware used it.  Tools/scripts/decode_devid.py
shows this comment as a warning when decoding such an ID.
2026-09-16 17:18:56 +10:00
Peter Barker a4e55aa914 AC_AttitudeControl: place PosControl parameter conversion tables in rodata 2026-09-16 17:07:48 +10:00
Peter Barker a526f304a5 AP_Camera: place parameter conversion table in rodata 2026-09-16 17:07:48 +10:00
Peter Barker 19629454ea AP_GPS: place parameter conversion table in rodata 2026-09-16 17:07:48 +10:00
Peter Barker 0bc73575cd AP_Param: allow conversion tables to omit a shared old key
Parameter conversion tables whose entries all share an old key found at
runtime (e.g. via find_top_level_key_by_pointer()) cannot be constant
if the key is stored in each entry, so a static table is initialised at
runtime and kept in RAM.  Adding a ConversionInfoNoKey table type plus
convert_old_parameters() and convert_old_parameters_scaled() overloads
which take the key separately allows these tables to be placed in
.rodata.
2026-09-16 17:07:48 +10:00
Peter Barker 73a936a702 waf: make dangling-pointer warnings errors on gcc 16.1 and later 2026-09-16 17:07:48 +10:00
Peter Barker de411b3818 AP_ADSB: bound Sagetech GPS message field widths
The GPS message is a run of fixed-width ASCII fields, each exactly as
wide as the value it holds, with the terminating nul landing on the
first byte of the field which follows it.  Nothing bounded the
formatted values, so an out-of-range input would overflow its field and
shift everything after it, and gcc-16 rejects the latitude outright:

  AP_ADSB_Sagetech.cpp:497: error: 'snprintf' output may be truncated
  before the last format character [-Werror=format-truncation=]

Bound each component to the widest value its field can represent, and
share the formatting between the two Sagetech drivers rather than
duplicating it.

The seconds of the time of fix are now formatted as an integer rather
than as a float so that the width of the field is known; the
milliseconds are rounded and carried into the seconds, which gives
output identical to the previous "%06.3f" except on exact
half-millisecond ties.  The MXS driver converted its epoch to seconds
through a double, which can round up to the following second at
present-day epoch values; it now uses integer division.

Built for sparknavi-blue, which master does not currently build.
2026-09-15 11:13:23 +10:00
Peter BarkerandClaude Opus 5 e8d00f3993 autotest: add AHRSExternalNoAttitudeAirspeedIndex test
The External AHRS backend must report the airspeed sensor index even
when it has no attitude.  Plane cannot observe this, as it falls back
to DCM when External has no attitude; Copter does not fall back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 10:41:40 +10:00
Peter BarkerandClaude Fable 5.1 49b71e1f29 autotest: add AHRSActiveAirspeedIndex test
Each AHRS backend now fills in the index of the airspeed sensor it is
using.  A backend which fails to do so reports index zero, which is
indistinguishable from the first sensor at the default ARSPD_PRIMARY,
so the existing affinity tests do not catch it.

Make the second sensor primary and check AIRSPEED.flags under DCM,
EKF2, EKF3, SIM and External in turn, waiting for each backend's
"active" announcement so a fallback to DCM cannot pass on its behalf.

Deleting the assignment from the DCM or External backend makes the
test fail at that backend's stage.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 10:41:40 +10:00
Peter Barker bdab7791df AP_AHRS: move active airspeed sensor result into Estimates structure 2026-09-15 10:41:40 +10:00
Peter Barker d7c87a46b6 AP_AHRS: collapse airspeed_sensor_enabled back into sole caller 2026-09-15 10:41:40 +10:00
Peter Barker e25ed5159f AP_AHRS: correct defines around using airspeed sensor
we don't need to constrain via the GPS data, so stop requiring it to return the airspeed sensor data
2026-09-15 10:41:40 +10:00
Peter BarkerandClaude Opus 5 fbf750c2ca Tools: honour MAVPROXY_CMD everywhere we run MAVProxy
MAVPROXY_CMD exists so you can point the tooling at a MAVProxy other
than the first "mavproxy.py" on PATH - a virtualenv, or a checkout you
are debugging against.  pysim/util.py reads it, but three other places
which launch MAVProxy spell the name out and so quietly run the wrong
one:

 - sim_vehicle.py, which is the most surprising of the three, since it
   already imports pysim.util for everything else it needs.  Under
   cygwin the default stays mavproxy.exe; an explicit MAVPROXY_CMD now
   wins there too.
 - Tools/renode/test_all.py, which also names it in the error it prints
   when it cannot be found, so that now names what was actually looked
   for.
 - the ros2 MAVProxy launch action.

Behaviour is unchanged when MAVPROXY_CMD is unset: mavproxy_cmd()
defaults to the same "mavproxy.py" these were hard-coding.

Checked sim_vehicle.py's assembled command and Tools/renode/test_all.py's
lookup both ways - unset gives "mavproxy.py" as before, set gives the
named path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 09:47:09 +10:00
Peter BarkerandClaude Opus 5 cd8a2df5fa autotest: skip MAVFTPCrcCompareMAVProxy only where crccmp is missing
The test drives "ftp crclocal" and "ftp crccmp".  MAVProxy grew those in
328d7de20 (2026-07-27) and has not cut a release since - the newest tag,
v1.8.74, is from 2025-08-02 and contains neither - so on a released
MAVProxy "ftp crclocal" falls through to the usage print and the test
waits out its 60s pexpect timeout.

Skipping it unconditionally would cost real coverage: build_ci.sh
installs MAVProxy by cloning master, which does have both commands, so
the test runs and passes in CI today.  A version gate would not work
either, because MAVProxy master still calls itself 1.8.74 - the same
version the release reports - so any mavproxy_version_gt() test would
disable the test in CI as well.

Ask the ftp module whether it implements the command instead, and skip
only where it does not.  Nothing has to be un-done later: the skip stops
applying by itself once the local MAVProxy has crccmp.  Keeping this in
disabled_tests() rather than returning early inside the test means the
skip is still reported in the run summary and the JUnit report.

Ask the MAVProxy we are actually going to run, not the one this process
could import.  MAVPROXY_CMD can name a MAVProxy in another virtualenv,
which is the whole point of the variable, and an in-process "import
MAVProxy" would then answer for the wrong install - saying the command
is present when the MAVProxy under test lacks it, which is exactly the
60s timeout this is meant to avoid.  Take the interpreter out of the
mavproxy script's shebang and put the question to that, keeping the
lookup next to mavproxy_cmd() in util.py where MAVPROXY_CMD is read.

Verified four ways: with crccmp present the entry is absent and
test.Plane.MAVFTPCrcCompareMAVProxy passes; with MAVPROXY_CMD pointing
at a stub install whose ftp module has no crccmp the probe reports False
and the entry appears, while an in-process import in that same run still
says True; and with MAVPROXY_CMD naming a path that does not exist the
probe returns "don't know" and the test is left enabled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 09:47:09 +10:00
Peter Barker 35356c656c autotest: test DO_REPOSITION is refused if GUIDED cannot be entered
Fails without the preceding fix: the command is ACCEPTED and the vehicle,
still in AUTO, turns away from its mission leg towards the reposition
target.
2026-09-14 19:59:12 +10:00
Peter Barker 0d3e2aaa8e Plane: fail DO_REPOSITION if GUIDED cannot be entered
When DO_REPOSITION asked for a change into GUIDED and the mode change
was refused (for example GUIDED being blocked by FLTMODE_GCSBLOCK) the
result of set_mode() was ignored.  The requested location was still
loaded with set_guided_WP() and the command was ACCEPTED, so a vehicle
in AUTO stayed in AUTO but flew towards the reposition target.

Return MAV_RESULT_FAILED instead, leaving the current mode's navigation
alone.
2026-09-14 19:59:12 +10:00
Peter BarkerandClaude Opus 5 f47861a374 .github: test_coverage: keep going when a coverage test suite fails
run_coverage.py now exits on the first failing test suite by default;
keep running the remaining suites so we still get a coverage report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 18:58:28 +10:00
Peter BarkerandClaude Opus 5 3f73e5ad1f Tools: make run_coverage.py stop at errors, add a flag to keep going on errors
use as a diagnostic tool was limited when it would exit on some failures but not on others.

Make it exit on failures by default, add a flag to allow a user to get consistent behaviour the other way

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 18:58:28 +10:00
Peter Barker 7dbc76fb1c Tools: enable math index checks for every build.Rover CI job
The rover workflow's build job primes ccache with
--enable-math-check-indexes, matching sitltest-rover and
sitltest-sailboat, which both pass "Rover" as the run_autotest name.
sitltest-balancebot passes "BalanceBot", so it configured without the
flag, missed the cache on 872 of 1382 compiles and spent 6m33s
building ardurover against 14s in the other two jobs.

Key the flag on the build step rather than the name, so BalanceBot
builds the same binary as the other build.Rover jobs.
2026-09-14 18:58:17 +10:00
Peter Barker 50ed390939 autotest: IE24: set failsafes so vehicle disarms on low/crit battery
this test was relaying on the vehicle disarming even with an action of NONE.  Since we're changing that behaviour, change the test to set the failsafe to a value which will disarm the vehicle
2026-09-14 12:44:42 +10:00
Peter Barker 22bd42f6c8 autotest: add test for battery instant-disarm on failsafe when fs-action-NONE 2026-09-14 12:44:42 +10:00
Peter Barker 2aeb8bf242 Copter: do not disarm the vehicle on battery fs if fs is none 2026-09-14 12:44:42 +10:00
Peter Barker 37ea692edb autotest: check an entry which exactly fills a listing packet is sent
Lists a directory holding a file whose entry is exactly the 239 bytes a
listing payload carries, one a byte longer than that, and a short one.
The first has to be listed, the second cannot be and must not be, and the
third proves dropping the one which cannot be sent did not end the
listing.
2026-09-12 15:00:50 +10:00
Peter Barker 4cedc1e346 GCS_MAVLink: list an entry which exactly fills a listing packet
An entry needing exactly as many bytes as the payload holds was treated as
unsendable and dropped. It does fit: AP_HAL::Util::vsnprintf builds its
BufferPrinter with size-1 and then writes the terminator itself at
str[size-1], and the byte that overwrites is the entry's own trailing NUL,
so the encoding which lands in the buffer is the one intended.

Compare against the size rather than allowing it, in all three places, so
the two packing loops still agree on what can never be sent.
2026-09-12 15:00:50 +10:00
Peter Barker b4697f8189 autotest: check the root directory lists its files
Puts a file and a directory in the root, lists it both with and without
times, and checks both come back - and, with times, that they carry the
modification time they were given.
2026-09-12 15:00:50 +10:00
Peter Barker 2a18e59e96 GCS_MAVLink: do not double the separator when listing the root
The path of the directory being listed is put in front of each entry's
name in order to stat it, with a "/" between. The root's path is already
just "/", so that produced "//name".

Most filesystems collapse that - FatFs skips duplicated separators
(ff.c:3019) and so does littlefs (lfs.c:1503) - but SITL's map_filename()
strips exactly one leading "/", so "//name" escapes to the host root. The
stat then fails, and a failed stat drops the entry, so every file in the
root went missing and the listing came back with directories only.

ArduPilot's own backend_by_path() also strips exactly one leading slash,
so a doubled separator would likewise miss a virtual backend.
2026-09-12 15:00:50 +10:00
Peter Barker f30be0bdea autotest: check a short FTP reply carries nothing past its size
Lists a directory to leave entries in the reply buffer, then asks past the
end of that listing, and checks the one byte NAK which comes back has
nothing but zeros behind the error code.
2026-09-12 15:00:50 +10:00