opendir() took one of the four directory records, and kept it when the
directory turned out not to exist. Four such attempts left every later
ROMFS opendir() failing with ENFILE until a reboot; over MAVFTP, four
listings of a missing @ROMFS path were enough. It also returned without
setting errno.
Free the record and set ENOENT.
Reading SITL's 300 character ROMFS names must give names cut short and
terminated, and ending the directory's name at its separator must not
write into another open listing's entry. Both fail against the readdir()
these follow.
readdir() ends a directory's name by writing a terminator at the
directory separator's index, which is past the end of d_name for a
directory name that long. Only shorten the name to the directory where
that falls within the name as copied.
readdir() copied the name with strncpy(), which leaves it unterminated
when it fills d_name, so anything reading it as a string - GCS_FTP's
listing among them - could run off the end of it.
Truncate to leave room for the terminator, as the FATFS backend does.
Co-authored-by: David Buzz <davidbuzz@gmail.com>
readdir() copied at most sizeof(d_name) bytes including the terminator,
so a name as long as d_name was left without one. On ChibiOS d_name is
MAX_NAME_LEN (255) bytes and LittleFS allows 255 character names, so
such an entry's name ran on into d_type and, for a directory, beyond it,
for anything reading it as a string - GCS_FTP's listing among them.
Truncate to leave room for the terminator, as the FATFS backend does.
Neither of SITL's 300 character ROMFS names fits in a listing packet, so
listing their directory gives nothing, but finding them must not read or
write outside the names around them. Run under --asan, this caught
AP_ROMFS::dir_list() reading past the previous name.
SITL's ROMFS gains files which sort just before a directory of the same
name, at the top level and below it, so MAVFTPListROMFS checks such a
directory is still listed.
dir_list() lists a directory once, for its first file, by skipping any
file whose leading directory matches the previous file's. It compared
the directory's name without the separator after it, so "sub.txt",
which sorts just before "sub/", was taken for it and the directory was
never listed. At the top level the name was also taken to start one
character in.
Compare through the separator, from the start of the name.
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.
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.
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.
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
In AP_Baro_MS5837::_calculate_5837_02ba, the multiplication (dT * _cal_reg.c6) overflows a signed 32-bit integer when dT is positive (~250,000 at ~25-30 degC) and c6 is ~28,000, exceeding INT32_MAX (~7e9 vs 2.14e9). This resulted in truncated/invalid temperature readings (e.g. ~19 degC).
Cast dT to int64_t before multiplication to prevent overflow.
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.
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>
Fails without the fix (EKF height 2.5 m high above 5 m), with only the
baro offset held (3.0 m drop at liftoff) and with only the reset skipped
(2.5 m high). Takeoff only; the touchdown half of the fix is not covered.
With EK3_RNG_USE_HGT, Copter uses a range finder that reads on the ground
for height while taking off, so the baro offset filter runs while the
motors spool up and learns the prop-wash baro error as offset. ALT_HOLD's
takeoff ends as the vehicle leaves the ground, the source goes back to baro
there, and the offset carries the error into the flight: in SITL with
SIM_BARO_GEFF_M 3 the EKF height read 2.5 m high from then until landing.
While takeoff or touchdown is expected, do not update the offset, and do
not reset the height to the baro on switching to it. Either alone is not
enough: with only the offset held, the reset drops the height by the whole
error at liftoff (3.0 m); with only the reset skipped, the offset still
carries it (2.5 m). With both, -0.17 m worst in the takeoff and 0.03 m mean
above 5 m.
Baro drift is not learned while the flags are set, which on Copter
includes the whole time it sits armed on the ground. Learning only the
upward part of the error was tried: in SITL it did no better, and baro
noise ratchets it upwards (0.07 m after a 10 s armed wait with
SIM_BARO_RND 0.2). Fixed wing sets the flags for a launch rather than for
rotor wash, so it is left as it was.
The check is about aiding in flight. With the flow focus floor from #34292
the flow on the ground after touchdown is not fused, so relative aiding
stops before the disarm and would count against this test. Count only
between NOT_LANDED and LAND_COMPLETE.
Fail every compass in flight, remove optical flow until aiding stops,
then restore it. Aiding has to restart, which needs the gyro bias check
to ignore the Z axis while no yaw is being fused.
Covers no yaw source, a compass that stops delivering data and GPS yaw
lost. The simulated gyro has no bias, so any Z bias the EKF learns is
phantom. The yaw reference is removed at arming and the flow scale error
doubled, so the bias grows within 40 s of flight rather than 240 s: yaw
fused during the climb otherwise holds it down.
Flow has to have been fused for a zero bias to mean anything. XKF5 flow
innovations do not show that, as they are written before the innovation
gate and never cleared, so the test requires that flow fusion started
and that aiding never stopped while armed, which with flow as the only
aiding source means an update passed the gate at least every 5 s.
Debug build, max Z gyro bias in deg/s against a 0.1 limit. Merge-base:
no yaw source 0.26 to 0.27 (4 runs), compass lost 0.95 to 1.10 (4
runs), GPS yaw lost 1.09 to 1.26 (3 runs). With the fix: 0.00, 0.01 and
0.01 to 0.02 (3 runs). The test takes about 23 s.
Adds an additional check that fuseEulerYaw actually fused the yaw rather than just attempting to fuse it. The most likely reason they can be different is the yaw value's innovations are higher than the gate
On the ground with EK3_MAG_CAL 7 the compass yaw is fused as an anchor
before 3-axis fusion. If the 3-axis fusion then fails its innovation
check, last_mag_yaw_fuse_ms was not refreshed although a yaw update
was applied.
checkGyroCalStatus() only drops the Z axis from the delAngBiasLearned
test when no yaw source is configured. Optical flow no longer learns
the Z gyro bias while no yaw is being fused, so with a yaw source that
is configured but not fusing, such as a failed compass, P[12][12] stays
above the threshold. delAngBiasLearned then stays false, and once a
flow dropout has stopped aiding, readyToUseOptFlow() never lets it
restart.
Use the same fusion test as the flow mask, so a configured source that
is not being fused is treated like no yaw source.
SITL, flow-only Copter, all compasses failed in flight, flow removed
until aiding stopped and then restored: before, aiding did not restart
within 30 s; after, it restarted 1.0 s after flow returned. Boot on a
default compass and GPS Copter and on Plane is unchanged: compass yaw
is first fused 0.2 s and 2.0 s after covariance init, long before the
bias variances converge.
With optical flow as the horizontal aiding source and no yaw reference
being fused, heading and the Z gyro bias are only poorly observable.
Flow fusion can absorb a flow-velocity error as a phantom Z gyro bias,
which then drifts yaw and walks the dead-reckoned position.
Mask state 12 out of the flow Kalman update unless GPS, compass or
external nav yaw has been fused within the last 5 s. The test reads
fusion timestamps, never the configured source: a source that is
configured but lost in flight, or a compass that stops delivering
data, is the case the mask is for. GPS yaw already records
last_gps_yaw_fuse_ms; external nav and the compass now record theirs
where a fusion is applied (last_extnav_yaw_fusion_ms is refreshed by
rejected samples too), and a yaw fusion only counts if FinishFusion()
applied it. Anything else inhibits, which is safe because any real yaw
fusion learns the bias through its own gains.
X/Y gyro bias remain observable via gravity and are unaffected. This is
the same K-only mask FuseVelPosNED already applies to poorly observable
gyro bias axes in AID_NONE.
SITL, flow-only Loiter for 240 s with a 20 percent flow scale error and
no real gyro bias, maximum learned Z gyro bias with no yaw source 0.30
-> 0.00 deg/s, with all compasses failed 0.30 -> 0.03, with GPS yaw
lost 0.23 -> 0.01.
publish_sens_para() declared baro_ok and mag_ok unconditionally but only
used them inside the AP_BARO_EXTERNALAHRS_ENABLED and
AP_COMPASS_EXTERNALAHRS_ENABLED blocks. With either feature disabled the
variable is unused and -Werror=unused-variable fails the build:
./waf configure --board sitl --disable-EXTERNALAHRS_BARO && ./waf copter
AP_ExternalAHRS_Aeron_plx.cpp:432:16: error: unused variable 'baro_ok'
Move each declaration inside the block that uses it. No behaviour change
with the default feature set.
The driver stamps last_sens_ms and friends at parse time, and only the
reader thread ever parsed: update() was an empty stub. healthy() therefore
measured how recently that thread had been scheduled rather than how
recently the PLX had sent anything.
In SITL a non-main thread's wall-clock scheduling delay becomes
speedup-multiplied simulated time, so an ordinary 1-2 ms preemption at
SIM_SPEEDUP=20 exceeds the 40 ms SENS_PARA deadline. The spurious
unhealthy drops AP_AHRS to DCM, which fails the arming check and makes
the AeronEAHRS autotest fail intermittently.
update() now calls check_and_decode(), serialised against the reader
thread by a new parse_sem, as other EAHRS backends already do. The lock
is required for correctness, not hardening: the UART ring buffer is a
single-consumer structure, so two unserialised readers would each copy
and advance past the same bytes. A setup_complete guard is added to
check_and_decode() so both callers share one readiness check.
available() is called inside parse_sem rather than before it: on SITL it
can reach a blocking accept() via _check_connection(), which two
unserialised callers could race into. SENS_TIMEOUT_MS is unchanged.
On HALs that serve UART reads only to the thread that claimed the port
(ChibiOS, ESP32) the reader thread owns it and the main-thread call
returns having read nothing. That is intentional: those targets schedule
the reader thread in real time and do not exhibit this starvation, so on
flight hardware this part of the change is a no-op.
healthy() also sampled the clock before reading the packet timestamps.
The reader thread runs at PRIORITY_SPI, above the main thread, and can
stamp a newer millisecond between the two reads; (now - stamp) then
underflows to ~2^32 and health reads false for one loop, bouncing
AP_AHRS to DCM and back. Read the timestamps first: millis() is
monotonic and the stamps are only ever assigned from it, so sampling the
clock afterwards guarantees now >= stamp. This part applies on all
targets.
Renames and rescales the Copter and QuadPlane parameters that changed
name or units in 4.7 (attitude, position and waypoint controllers,
loiter, circle, RTL, land, pilot, rangefinder, MAV_ and stream rate
parameters), converts ARMING_CHECK to ARMING_SKIPCHK and moves the
MAVLink bits of SERIALn_OPTIONS into MAVn_OPTIONS. Files are converted
in place or into an output directory, --patch selects the 4.7.0 or 4.7.1
names and the vehicle is detected from the file content.
Move the parameter file parsing, rescaling and rewriting into importable
helpers so that other conversion scripts can reuse them. The standalone
interface is unchanged apart from a new --sig-digits option (default 3).
QGroundControl files are now handled, names are matched exactly instead
of by prefix, and separators, comments and untouched lines are preserved.
Add MountAVTCM62DualImageStartCapture covering a single image on all
cameras and on each camera, a fixed count via COMMAND_LONG, capture
until stopped via IMAGE_STOP_CAPTURE, and rejection of a zero interval
with multiple images, a negative camera ID and an absent camera slot.
Extend MountAVTCM62DualMission with an all-cameras mission item and
check MountAVTCM62 rejects an unconfigured slot.
Unconfigured and absent camera slots are DENIED by the camera selector
resolution rather than FAILED as in the original tests.
Based on Peter Barker's work in ArduPilot/ardupilot#33900.
Co-authored-by: Peter Barker <pbarker@barker.dropbear.id.au>
IMAGE_START_CAPTURE asking for more than one image with a zero interval
cannot be honoured. It was reported as FAILED by the interval check in
take_multiple_pictures; report DENIED from the command handler instead,
matching the other parameter rejections and the mission path.
Based on Peter Barker's work in ArduPilot/ardupilot#33900.
Co-authored-by: Peter Barker <pbarker@barker.dropbear.id.au>
The simulator claims basic zoom and focus support so those camera
command paths can be exercised. Record what the real CM62 supports
according to the vendor, and the narrower range and focus types the
simulator actually handles, instead of calling the flags speculative.
Based on Peter Barker's work in ArduPilot/ardupilot#33900.
Co-authored-by: Peter Barker <pbarker@barker.dropbear.id.au>
The analyser no longer reports the GCS.h num_intervals finding, so
retaining its suppression fails CI. Keep the separate suppression for
the remaining read in GCS_Common.cpp.
FBWB and CRUISE circuit legs require a minimum distance, not arrival
inside a narrow band. Accept distances beyond the threshold so
high-speedup position samples cannot skip the success window.
Exercise MT11 and AVT camera and gimbal behaviour, telemetry-driven
targeting, RTSP bounds, target refresh, capture-status expiry and
backpressure-safe stream replies.
Verify unicast routing and opt-in telemetry, extended parameter replies
from isolated links, forced home and origin events, and MT11 directory
listing and XML downloads through a unicast connection.
Check native camera identity across isolated and broadcast links,
default, configured and colliding component IDs, mixed native and servo
cameras, and native versus configured mount associations.
Cover camera and gimbal selectors for live commands and missions,
including legacy NaN values under floating-point traps, video stream
selection, native gimbal IDs, cached attitude frames and FC-owned
camera ACK identity. Fix the MAVFTP import ordering required by Ruff.
Model mode, recording state and capture status for combined camera and
gimbal simulators, and let each device supply its resolution, stream
information and camera definition metadata.
Request vehicle position/velocity and attitude over the gimbal link and
combine them with the three simulated encoders instead of using
simulation truth for global targeting. Stop targeting when telemetry
expires and retry message requests. Unit test prediction, encoder
composition from non-trivial attitudes, and command/feedback frames.
Add the MT11 combined camera/gimbal with visible and thermal RTSP
streams, bounded parsing, queued TCP output and tested frame pacing.
Advertise a component-addressed camera.xml URI and serve the embedded
read-only definition over MAVFTP with directory listing, ordinary and
burst reads, session validation and retry replies.
Validate camera and gimbal selector parameters at upload, treating NaN
as unset where the field was previously reserved.
Store the camera ID and status frequency for VIDEO_START_CAPTURE and
VIDEO_STOP_CAPTURE with a storage tag so previously stored items keep
their camera-slot meaning.
Execute camera items by converting back to a command and calling
AP_Camera::handle_command, removing the duplicated dispatch.
Resolve gimbal selectors through AP_Mount for pitch/yaw, ROI and
WPNEXT_OFFSET items. ROI items with a nonzero selector affect only the
selected mount; selector zero keeps the vehicle-specific yaw behaviour.
Cache bounded stream lists and resume replies independently on each
GCS link after transmit backpressure. Expire remote capture status
after three seconds, retain locally scheduled interval capture, and
back off unanswered status requests.
Preserve native camera identity in cached replies and isolated-link
broadcasts, and suppress synthetic FC-owned status for native cameras.
Restore configured mount associations in cached information only when
a same-system camera advertises none.
Add CAMn_COMPID (0 or 7-255) so camera-v2 discovery can use a
non-default component ID. The first slot owns a colliding ID; duplicate
or invalid IDs warn and disable discovery.
Resolve command selectors as component IDs or legacy slots 1-6 with the
same rules for live commands and missions. NaN in formerly reserved
selector fields means unset. Video commands with a nonzero camera
selector treat param1 as a stream ID and pass the status frequency
through; without one they keep the old camera-slot interpretation.
Fill camera_device_id in camera information, settings, capture status,
field of view and stream messages, and document the routing and
selector design.
Send changed targets immediately and refresh unchanged targets at a
configurable rate. Keep vehicle attitude output configurable with a
50 Hz default, use absolute global ROI targets and explicit yaw frames,
and require a separate link for each camera/gimbal unit.
Resolve gimbal selectors as component IDs (7-255) or legacy mount slots
(1-6), rejecting fractional, negative, NaN and out-of-range values
instead of wrapping them into another mount. Zero still selects the
primary mount.
Advertise MAVLink gimbals by their component ID in GIMBAL_MANAGER
information and status and in camera associations. Relay cached native
GIMBAL_DEVICE_ATTITUDE_STATUS with the gimbal's own identity and
attitude frame.
Handle explicitly addressed ROI_LOCATION, ROI_NONE and ROI_SYSID mount
selection, and pass camera_device_id through mount-backed camera
information and settings.
Add MAVn_OPTIONS bit 4 for exact learned-route forwarding without
broadcast traffic or default telemetry streams. Retain heartbeats and
explicit message requests, and suppress unsolicited global broadcasts
such as home and origin updates on those links.
Process broadcasts arriving on private and unicast links locally
without forwarding them, so the associated camera backend can relay
targetless PARAM_EXT_VALUE/ACK replies to normal links while other
isolated destinations stay protected. Dispatch camera capture status,
video stream information, camera telemetry and heartbeats to AP_Camera
so that backend can relay selected broadcasts while unrelated devices
remain isolated.
Route DO_SET_ROI_LOCATION and DO_SET_ROI_NONE with a nonzero gimbal
selector to the selected mount only; selector zero or NaN keeps the
vehicle behaviour. Legacy DO_SET_ROI keeps param1 as the ROI mode.
Report the FC-owned camera slot in COMMAND_ACK result_param2 for accepted
commands, and reject fractional or out-of-range CAMERA_TRACK_RECTANGLE
selectors before the COMMAND_LONG conversion truncates them to an integer.
Sync the camera device ID fields and the camera/gimbal selector
parameters from upstream common and development definitions.
The upstream sentence saying DO_SET_ROI_LOCATION and DO_SET_ROI_NONE
must not be sent to a gimbal device is omitted from the fork. The gimbal
protocol v2 device interface has no location setpoint, and AP_Mount
sends those two commands to a device that advertises
GIMBAL_DEVICE_CAP_FLAGS_CAN_POINT_LOCATION_GLOBAL so it can track the
location from its own position telemetry. DO_SET_ROI_WPNEXT_OFFSET and
DO_SET_ROI_SYSID keep the restriction.
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.