Skip to content

Set param updates - #1994

Open
amilcarlucas wants to merge 2 commits into
masterfrom
set_param_updates
Open

Set param updates#1994
amilcarlucas wants to merge 2 commits into
masterfrom
set_param_updates

Conversation

@amilcarlucas

Copy link
Copy Markdown
Collaborator

Description

Set param updates

Checklist

  • Run pre-commit checks locally
  • Verified by a human programmer
  • All commits are signed off (use git commit --signoff)
  • Code follows our coding standards
  • Documentation updated if needed
  • No breaking changes or properly documented

Testing

Describe how you tested these changes:

  • Unit tests pass
  • Integration tests pass
  • Manual testing performed
  • Tested on flight controller hardware

Copilot AI lite review requested due to automatic review settings August 28, 2026 15:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Updates flight-controller parameter write behavior to detect and surface MAVLink-2 PARAM_ERROR rejections (newer ArduPilot firmware), while keeping legacy “send-only” semantics when no acknowledgement is emitted.

Changes:

  • Add a pymavlink compatibility layer to decode PARAM_ERROR and map error codes to user-facing messages.
  • Update FlightControllerParams.set_param() to poll briefly for PARAM_ERROR and return a meaningful failure when received.
  • Improve fakes/tests for MAVLink connection caching and message-type filtering; add tests for firmware-rejected vs legacy behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_frontend_tkinter_log_analysis.py Minor formatting-only change in tests.
tests/test_backend_flightcontroller_params.py Adds tests for PARAM_ERROR handling and legacy timeout behavior.
tests/test_backend_flightcontroller_factory_mavlink.py Updates fake factory expectations and adds message-type filtering tests.
ardupilot_methodic_configurator/backend_mavlink_param_error.py Introduces runtime registration/decoding helpers for MAVLink PARAM_ERROR.
ardupilot_methodic_configurator/backend_flightcontroller_params.py Implements PARAM_ERROR polling and error mapping in set_param().
ardupilot_methodic_configurator/backend_flightcontroller_factory_mavlink.py Stores created fake connections and adds recv_match(type=...) filtering.
ARCHITECTURE_2_flight_controller_communication.md Updates architecture/docs to reflect current synchronous behavior and PARAM_ERROR support.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

ordered_fieldnames: ClassVar[list[str]] = ["param_index", "target_system", "target_component", "param_id", "error"]
fieldtypes: ClassVar[list[str]] = ["uint8_t", "uint8_t", "char", "int16_t", "uint8_t"]
orders: ClassVar[list[int]] = [1, 2, 3, 0, 4]
lengths: ClassVar[list[int]] = [1, 1, 1, 1, 1]
Comment on lines +28 to +34
The definition matches MAVLink common.xml message 345. Re-registration is harmless
and also handles applications that change pymavlink's dialect at runtime.

"""
mavlink = mavutil.mavlink
if PARAM_ERROR_MESSAGE_ID in mavlink.mavlink_map:
return
Comment on lines +355 to +365
while time_time() - start_time < self.PARAM_SET_PROPAGATION_DELAY:
message = self.master.recv_match(type="PARAM_ERROR", blocking=False)
if message is not None:
error_code = get_param_error_message(message, param_name)
if error_code is not None:
return error_code
# Test doubles or malformed data should not turn into a half-second
# busy wait. Real pymavlink filtering only returns PARAM_ERROR here.
if not isinstance(getattr(message, "param_id", None), (bytes, str)):
return None
time_sleep(self.PARAM_FETCH_POLL_DELAY)
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

☂️ Code Coverage

current status: ✅

Overall Coverage

Statements Covered Coverage Threshold Status
18927 16924 89% 89% 🟢

New Files

No new covered files...

Modified Files

No covered modified files...

updated for commit: 24ef64c by action🐍

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Test Results

    2 files      2 suites   13m 47s ⏱️
4 890 tests 4 883 ✅  7 💤 0 ❌
9 722 runs  9 701 ✅ 21 💤 0 ❌

Results for commit 65fdfd0.

♻️ This comment has been updated with latest results.

@amilcarlucas
amilcarlucas requested a lite review from Copilot August 31, 2026 13:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment on lines +355 to +359
for message in self._pending_param_errors:
error_code = get_param_error_message(message, param_name)
if error_code is not None:
self._pending_param_errors.remove(message)
return error_code
Comment on lines +170 to +178
mock_master = MagicMock()
mock_master.recv_match.side_effect = [SimpleNamespace(param_id="SECOND_PARAM", error=5)]
mock_conn_mgr = Mock()
mock_conn_mgr.master = mock_master
mock_conn_mgr.info = FlightControllerInfo()
params_mgr = FlightControllerParams(connection_manager=mock_conn_mgr)

with patch("ardupilot_methodic_configurator.backend_flightcontroller_params.time_time", side_effect=[0.0, 1.0]):
success, error = params_mgr.set_param("FIRST_PARAM", 1.0)
Comment on lines +331 to +336
error_code = self._wait_for_param_error(param_name)
if error_code is not None:
error_msg = self.PARAM_ERROR_MESSAGES.get(error_code, _("Flight controller rejected parameter write"))
error_msg = _("Failed to set %(name)s: %(error)s") % {"name": param_name, "error": error_msg}
logging_error(error_msg)
return False, error_msg
ordered_fieldnames: ClassVar[list[str]] = ["param_index", "target_system", "target_component", "param_id", "error"]
fieldtypes: ClassVar[list[str]] = ["uint8_t", "uint8_t", "char", "int16_t", "uint8_t"]
orders: ClassVar[list[int]] = [1, 2, 3, 0, 4]
lengths: ClassVar[list[int]] = [1, 1, 1, 1, 1]
@coveralls

coveralls commented Aug 31, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 33611905508

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage increased (+0.006%) to 89.404%

Details

  • Coverage increased (+0.006%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 14 coverage regressions across 2 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

14 previously-covered lines in 2 files lost coverage.

File Lines Losing Coverage Coverage
backend_flightcontroller_factory_mavlink.py 8 92.45%
backend_flightcontroller_params.py 6 97.32%

Coverage Stats

Coverage Status
Relevant Lines: 19140
Covered Lines: 17112
Line Coverage: 89.4%
Relevant Branches: 5752
Covered Branches: 4753
Branch Coverage: 82.63%
Branches in Coverage %: No
Coverage Strength: 2.66 hits per line

💛 - Coveralls

@amilcarlucas
amilcarlucas requested a lite review from Copilot September 1, 2026 00:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Comment on lines +127 to +142
if condition is not None:
error_message = "Buffered receive does not support conditions"
raise NotImplementedError(error_message)

message_types = None if type is None else {type} if isinstance(type, str) else set(type)
start_time = monotonic()
while True:
# A busy telemetry link can always have another unrelated message
# ready. Check the deadline before every read so a filtered wait
# cannot indefinitely drain and buffer that stream.
if timeout is not None and monotonic() - start_time >= timeout:
return None
message = self._pop_pending_matching(message_types)
if message is None:
recv_msg = self._connection.recv_msg # type: ignore[attr-defined]
message = recv_msg()
Comment on lines +54 to +62
fieldnames: ClassVar[list[str]] = ["target_system", "target_component", "param_id", "param_index", "error"]
ordered_fieldnames: ClassVar[list[str]] = ["param_index", "target_system", "target_component", "param_id", "error"]
fieldtypes: ClassVar[list[str]] = ["uint8_t", "uint8_t", "char", "int16_t", "uint8_t"]
orders: ClassVar[list[int]] = [1, 2, 3, 0, 4]
lengths: ClassVar[list[int]] = [1, 1, 1, 1, 1]
array_lengths: ClassVar[list[int]] = [0, 0, 16, 0, 0]
crc_extra: ClassVar[int] = 209
unpacker: ClassVar[struct.Struct] = struct.Struct("<hBB16sB")
native_format: ClassVar[bytearray] = bytearray(b"<hBB16sB")
Comment on lines +84 to +97
def pack(self, mav: object, force_mavlink1: bool = False) -> bytes:
"""Serialize using the same implementation generated by pymavlink."""
return self._pack( # type: ignore[attr-defined]
mav,
self.crc_extra,
self.unpacker.pack(
self.param_index,
self.target_system,
self.target_component,
self.param_id.encode("ascii"),
self.error,
),
force_mavlink1=force_mavlink1,
)
Comment on lines +369 to +370
while time_monotonic() - start_time < self.PARAM_SET_PROPAGATION_DELAY:
remaining = self.PARAM_SET_PROPAGATION_DELAY - (time_monotonic() - start_time)
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
Detect the connected ArduPilot firmware version from AUTOPILOT_VERSION and
enable PARAM_ERROR acknowledgement handling only for firmware 4.7.0 and newer.
Older firmware keeps the original send-only parameter-write behavior without
an unnecessary response timeout.

Add a local MAVLink-2 PARAM_ERROR compatibility decoder for pymavlink versions
that do not define message 345. Preserve unrelated PARAM_VALUE messages received
while waiting for an acknowledgement so later parameter operations can consume
them safely.

Extend the MAVLink connection test double with message filtering, unfiltered
message reception, connection lookup, and parameter-send support. Add regression
tests covering firmware-version boundaries, PARAM_ERROR decoding, stale replies,
message preservation, and legacy write performance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants