Greenfield Steps 1-6 baseline for the autopilot rewrite from legacy Qt/C++ to a Rust workspace. - Remove legacy Qt/C++ tree (ai_controller, drone_controller, misc/camera, python_scaffold, root Dockerfile, autopilot.pro, legacy main.py / requirements.txt). - Add _docs/00_problem (problem, restrictions, acceptance criteria, security approach, input data + fixtures). - Add _docs/01_solution/solution_draft01. - Add _docs/02_document (architecture, system-flows, data_model, glossary, decision-rationale, deployment, 13 component descriptions, tests/ specs, FINAL_report, module-layout). - Add _docs/02_tasks/todo with 47 task specs (AZ-640..AZ-686, one bootstrap + 46 component tasks) and _dependencies_table.md. - Add .cursor/rules/artifact-srp.mdc (single-responsibility rule for canonical _docs artifacts). - Track autodev state in _docs/_autodev_state.md (Step 6 completed, ready for Step 7 Implement). Jira: bootstrap AZ-626; component epics AZ-627..AZ-639; tasks AZ-640..AZ-686. Total complexity 173 points across 12 epics. Co-authored-by: Cursor <cursoragent@cursor.com>
4.3 KiB
MAVLink Message Codec (§7.7 Surface)
Task: AZ-642_mavlink_codec Name: MAVLink v2 encode/decode for the §7.7 surface Description: Encode and decode the ~10–15 MAVLink v2 messages this codebase needs (the §7.7 surface only) with strict validation. Complexity: 5 points Dependencies: AZ-640_initial_structure Component: mavlink_layer Tracker: AZ-642 Epic: AZ-637
Problem
Autopilot speaks a deliberately narrow MAVLink command surface (per architecture.md §7.7 — ~10–15 messages). Adding messages outside that list requires explicit design review. A hand-rolled MAVLink v2 codec must encode outbound messages with correct sequence numbers, system / component IDs, and (when enabled) signing, and decode inbound messages with strict validation — rejecting malformed frames, unknown IDs, and signing failures.
Outcome
- Outbound encoder produces wire-correct MAVLink v2 frames for the message surface in §7.7 with monotonically incrementing per-link sequence numbers.
- Inbound decoder parses the same surface, rejecting malformed frames, unknown message IDs, and frames with sequence-number gaps (logged, not hard-failed).
- Decoded messages are exposed as a typed
MavlinkMessageenum (one variant per supported message kind) on the inbound channel. - Per-message-kind parse error counters are exposed via
health().
Scope
Included
- Encode + decode for
HEARTBEAT(bidir),COMMAND_LONGoutbound subset (arm/disarm, takeoff, set-mode, change-speed, change-alt, land, RTL),COMMAND_ACKinbound,MISSION_COUNT,MISSION_REQUEST_INT,MISSION_ITEM_INT,MISSION_ACK,MISSION_SET_CURRENT,MISSION_CURRENT,MISSION_ITEM_REACHED,MISSION_CLEAR_ALL,GLOBAL_POSITION_INT,ATTITUDE,SYS_STATUS,EXTENDED_SYS_STATE,STATUSTEXT,SET_MODE. - Per-link outbound
tx_seqcounter with wrap-around handling. - Strict size + CRC validation; reject malformed frames.
- Unknown message IDs counted and dropped (not hard-failed).
- Sequence-number gap detection (logged, not fatal).
Excluded
- Transport and reconnect (task 02).
- Heartbeat scheduling (task 02).
- Ack demultiplexing to callers (task 04).
- MAVLink-2 signing (task 04).
- Any message not in the §7.7 surface — adding new messages requires design review.
Acceptance Criteria
AC-1: Round-trip every supported message
Given the encoder produces a frame for each message kind in the §7.7 surface with deterministic field values
When the same frame is fed back through the decoder
Then the typed MavlinkMessage matches the original fields and parse_errors_total does not increment.
AC-2: Malformed frame is rejected
Given a byte buffer with a truncated payload or a wrong CRC
When the decoder consumes it
Then the frame is dropped, parse_errors_total{kind="crc" | "truncated"} increments by 1, and the codec continues processing subsequent bytes.
AC-3: Unknown message ID is counted, not fatal
Given an inbound frame with a message ID outside the §7.7 surface
When the decoder consumes it
Then the frame is dropped, parse_errors_total{kind="unknown_id"} increments by 1, and decoding continues.
AC-4: SITL round-trip
Given an ArduPilot SITL instance configured for udp://127.0.0.1:14550
When mavlink_layer emits a COMMAND_LONG for MAV_CMD_NAV_RETURN_TO_LAUNCH
Then SITL receives the command and replies with a matching COMMAND_ACK; the decoder emits a MavlinkMessage::CommandAck with result = MAV_RESULT_ACCEPTED.
Non-Functional Requirements
Performance
- Per-message encode + decode round-trip: ≤50 ms p99 on a healthy link (per
description.md §8).
Reliability
- No silent acceptance of malformed or signed-mismatch frames.
Constraints
- Hand-rolled — no third-party MAVLink SDK.
- Adding any message outside the §7.7 surface requires an explicit design review noted in the PR description.
Runtime Completeness
- Named capability: MAVLink v2 wire-correct encode/decode for the §7.7 command surface.
- Production code that must exist: real byte-level encoder + decoder; CRC computation; sequence number handling.
- Allowed external stubs: ArduPilot SITL is the conformance reference for the SITL round-trip AC.
- Unacceptable substitutes: a JSON or human-readable "MAVLink-like" envelope is not acceptable — the wire format must be MAVLink v2.