Update mavftp - #2018
Conversation
There was a problem hiding this comment.
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
This PR updates the project to use the upstream MAVFTP implementation (from pymavlink) and aligns related data-model and UI behavior with ArduPlane-specific frame-class semantics, while also syncing ArduPilot device-ID decoding utilities.
Changes:
- Replace many legacy MAVFTP constants/structures with upstream-aligned enums/types (
FtpError,DirectoryEntry) and update tests/callers accordingly. - Adjust frame-class handling so ArduPlane can treat
"Undefined"as valid and prefersQ_FRAME_*parameters where applicable. - Introduce / sync ArduPilot’s device-id decode script into the repo and update workflows and import sites.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit_data_model_vehicle_components_validation_constants.py | Updates expectations around "Undefined" frame class for ArduPlane only. |
| tests/test_data_model_vehicle_components_validation.py | Adds coverage for accepting "Undefined" frame class on ArduPlane. |
| tests/test_backend_mavftp_aux.py | Migrates tests from integer error constants to FtpError. |
| tests/test_backend_mavftp.py | Updates/extends MAVFTP tests for new error handling and callback behavior. |
| tests/test_backend_flightcontroller_sitl.py | Updates error handling to use FtpError values. |
| tests/test_backend_flightcontroller_files.py | Updates directory listing mocks to use DirectoryEntry. |
| tests/test_backend_flightcontroller_factory_mavftp.py | Improves MAVFTP factory tests by mocking ResetSessions ACK behavior. |
| tests/test_backend_flightcontroller_business_logic.py | Adds ArduPlane-specific preference for Q_FRAME_* in get_frame_info. |
| pyproject.toml | Excludes synced ArduPilot device-id decoder file from Ruff. |
| ardupilot_methodic_configurator/vehicle_templates/ArduPlane/normal_plane/00_default.param | Syncs/updates ArduPlane default params (large template update). |
| ardupilot_methodic_configurator/log_analysis/decode_devid_lib.py | Updates/syncs device-id decoding logic and CLI behavior. |
| ardupilot_methodic_configurator/log_analysis/data_model_vehicle_overview_sensor_rules.py | Switches imports to the new synced decode_devid module and adapts to new return type. |
| ardupilot_methodic_configurator/data_model_vehicle_components_validation.py | Allows "Undefined" frame class only for ArduPlane in UI choices. |
| ardupilot_methodic_configurator/data_model_vehicle_components_import.py | Passes firmware type into get_frame_info for ArduPlane behavior. |
| ardupilot_methodic_configurator/configuration_steps_ArduPlane.json | Adds derived-parameter rules for Q_FRAME_CLASS and autoimport hints. |
| ardupilot_methodic_configurator/backend_mavftp.py | Major MAVFTP refactor to upstream structures (pymavlink.mavftp_op), new error enum, listing entries, and new read/messaging logic. |
| ardupilot_methodic_configurator/backend_flightcontroller_params.py | Updates success checks to use FtpError.Success. |
| ardupilot_methodic_configurator/backend_flightcontroller_files.py | Updates MAVFTP integration for new error codes and directory listing type. |
| ardupilot_methodic_configurator/backend_flightcontroller_commands.py | Ensures get_frame_info receives detected vehicle_type. |
| ardupilot_methodic_configurator/backend_flightcontroller_business_logic.py | Adds ArduPlane-specific Q_FRAME_* preference in get_frame_info. |
| ardupilot_methodic_configurator/main.py | Sets vehicle type/version earlier so frame-class UI choices derive correctly. |
| .github/workflows/update_flightcontroller_ids.yml | Extends sync workflow to copy decode_devid.py and updates commit message/body. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| def __init__(self) -> None: |
| try: | ||
| size_int = int(size) | ||
| size = int(size_str) | ||
| except (ValueError, TypeError, OverflowError): | ||
| logging.error("Invalid file size: %s", size) | ||
| size_int = 0 | ||
| self.directory_listing[name] = size_int | ||
| self.total_size += size_int | ||
| logging.info(" %s\t%u", name, size_int) | ||
| logging.error("Invalid file size: %s", size_str) | ||
| size = 0 | ||
| self.list_temp_result.append( | ||
| DirectoryEntry(name=name, is_dir=False, size_b=size) |
| self.done = False | ||
|
|
||
| logging.info( | ||
| "Getting %s starting at %u reading %u bytes", |
| @@ -608,37 +735,69 @@ def cmd_get( | |||
| self.burst_size = int(self.ftp_settings.burst_read_size) | |||
| if self.burst_size < 1 or self.burst_size > 239: | |||
| self.burst_size = 239 | |||
|
|
||
| def __handle_open_ro_reply(self, op: FTP_OP, _m: object) -> MAVFTPReturn: | ||
| def __handle_open_ro_reply(self, op: FTP_OP, _m) -> MAVFTPReturn: | ||
| """Handle OP_OpenFileRO reply.""" | ||
| if op.opcode == OP_Ack: | ||
| if self.filename is None: | ||
| return MAVFTPReturn("OpenFileRO", ERR_FileNotFound) | ||
| return MAVFTPReturn("OpenFileRO", FtpError.FileNotFound) |
| return True | ||
| if self.op_start is None: | ||
| return True | ||
| if len(self.read_gaps) == 0 and ( | ||
| self.reached_eof or self.read_total >= self.requested_size |
| op_ret_name = operation_name or operation_name_dict.get(op.req_opcode, "Unknown") | ||
| op_ret_name = operation_name or operation_name_dict.get( | ||
| op.req_opcode, "Unknown" | ||
| ) |
| elif error_code == FtpError.FailErrno: | ||
| error_code = FtpError.NoFilesystemErrorInPayload | ||
| elif error_code not in [ | ||
| FtpError.Fail, |
| invalid_error_code = error_code | ||
| error_code = ERR_InvalidErrorCode | ||
| elif op.payload is not None and op.payload[0] == ERR_FailErrno and len_payload == 2: | ||
| error_code = FtpError.InvalidErrorCode | ||
| elif ( | ||
| op.payload is not None | ||
| and op.payload[0] == FtpError.FailErrno | ||
| and len_payload == 2 |
| type=float, | ||
| metavar="setting_value", | ||
| help="MAVFTP internal configuration parameter value.", | ||
| ) |
fa33b4b to
8691eac
Compare
Replace the local device ID decoder with ArduPilot's upstream Tools/scripts/decode_devid.py. Update sensor-rule integration for the upstream decoder API, preserve the copied-file disclaimer in the update workflow, and exclude the synchronized file from project-specific Ruff checks.
ArduPlane stores multicopter frame settings in Q_FRAME_CLASS and Q_FRAME_TYPE, unlike ArduCopter. Pass the vehicle type through frame extraction so ArduPlane explicitly prefers those parameters. Initialize the detected firmware type before importing parameters and creating component-editor widgets, ensuring the correct frame-class choices are used. Allow Undefined as a valid displayable frame class for normal fixed-wing ArduPlane configurations without a multicopter frame. Add regression coverage for parameter precedence and Plane validation.
Replace the local MAVFTP backend with pymavlink's implementation and adapt consumers to the FtpError and DirectoryEntry APIs. Prevent callback-owned downloads from writing virtual remote paths as local files, and update the related tests and fixtures.
8691eac to
9fee757
Compare
Description
Use upstream mavftp from pymavlink instead of out local forked copy
Thanks to @peterbarker this speeds up parameter download from 4 seconds to 40ms :)
Checklist
git commit --signoff)Testing
Describe how you tested these changes: