You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Copy file name to clipboardExpand all lines: ARCHITECTURE_2_flight_controller_communication.md
+38-18Lines changed: 38 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,9 @@ make MAVLink, MAVFTP, or command operations concurrent or non-blocking.
31
31
- ✅ Downloads parameters through MAVFTP when supported, with MAVLink `PARAM_REQUEST_LIST` fallback.
32
32
- ✅ Downloads parameter defaults only through the MAVFTP path.
33
33
- ✅ Validates parameter names and numeric value types before sending a parameter write.
34
-
- ⚠️ `set_param()` reports whether the send operation succeeded; MAVLink parameter writes have no command ACK here. Callers must use `fetch_param()` or re-download parameters to verify the controller state.
34
+
- ✅ Detects a matching MAVLink-2 `PARAM_ERROR` response from newer ArduPilot firmware and reports the controller's rejection reason.
35
+
- ⚠️ Older firmware does not acknowledge `PARAM_SET`; after the short `PARAM_ERROR` response window, `set_param()` can report only that the write was sent.
36
+
Callers that need positive confirmation must use `fetch_param()` or re-download parameters.
35
37
36
38
4.**Protocol Support**
37
39
- ✅ Uses pymavlink for MAVLink messages, connection creation, retries, and reconnect support.
@@ -49,13 +51,15 @@ make MAVLink, MAVFTP, or command operations concurrent or non-blocking.
49
51
50
52
1.**Performance**
51
53
- ✅ Uses MAVFTP when the controller advertises support and provides transfer progress callbacks.
52
-
- ⚠️ Download, command, and connection operations use polling and blocking waits. They should be invoked from an appropriate UI workflow to avoid blocking the event loop.
54
+
- ⚠️ Download, command, and connection operations use polling and blocking waits.
55
+
They should be invoked from an appropriate UI workflow to avoid blocking the event loop.
53
56
- ⚠️ No performance limit for parameter count or memory consumption is enforced or benchmarked by this component.
54
57
55
58
2.**Reliability** ⚠️ **PARTIALLY IMPLEMENTED**
56
59
- ✅ Checks for a connection before most controller operations and returns structured error messages for many failures.
57
60
- ✅ Verifies command results when the MAVLink command protocol provides `COMMAND_ACK`.
58
-
- ⚠️ Parameter writes require explicit read-back for verification.
61
+
- ✅ Reports explicit rejections from newer firmware through MAVLink-2 `PARAM_ERROR`.
62
+
- ⚠️ Parameter writes still require explicit read-back for positive verification, especially with older firmware that sends no response.
59
63
- ❌ **TODO**: Interrupted operations cannot be resumed from persisted state.
60
64
61
65
3.**Compatibility**
@@ -67,7 +71,7 @@ make MAVLink, MAVFTP, or command operations concurrent or non-blocking.
67
71
- ✅ Validates parameter names and value types before sending parameter writes.
68
72
- ⚠️ Message parsing and transport-level validation are delegated to pymavlink; this is not an end-to-end integrity or authorization guarantee.
69
73
- ❌ **TODO**: MAVLink signing/authentication is not implemented by this component.
70
-
- ⚠️ Parameter-write confirmation requires an explicit read-back, not a `set_param()` acknowledgement.
74
+
- ⚠️ Newer firmware can explicitly reject writes with `PARAM_ERROR`, but positive parameter-write confirmation still requires an explicit read-back.
71
75
72
76
## Architecture
73
77
@@ -101,13 +105,15 @@ and the parameter dictionary); the ownership and mutation rules above are the re
-**Purpose**: Discovers connection choices, establishes and closes MAVLink connections, selects a supported autopilot from heartbeats, and populates `FlightControllerInfo`.
108
+
-**Purpose**: Discovers connection choices, establishes and closes MAVLink connections, and selects a supported
109
+
autopilot from heartbeats before populating `FlightControllerInfo`.
105
110
-**Key methods**:
106
111
-`connect()` — connects to an explicit device or tries auto-detected choices.
107
112
-`disconnect()` — closes the current connection, clears the banner buffer, and resets controller information.
108
113
-`discover_connections(preserved_connections)` — merges locally enumerated serial ports, configured network endpoints, and persisted choices.
109
114
-`_register_and_try_connect()` and `create_connection_with_retry()` — internal connection helpers.
110
-
-**Connection validation**: `_detect_vehicles_from_heartbeats()` is used during connection establishment; `_retrieve_autopilot_version_and_banner()` then requests controller details.
115
+
-**Connection validation**: `_detect_vehicles_from_heartbeats()` is used during connection establishment;
116
+
`_retrieve_autopilot_version_and_banner()` then requests controller details.
111
117
-**Dependencies**: pymavlink, pyserial port discovery, `FlightControllerInfo`, time, and logging.
112
118
113
119
#### Parameters Manager
@@ -164,7 +170,8 @@ and the parameter dictionary); the ownership and mutation rules above are the re
164
170
165
171
-**File**: `data_model_flightcontroller_info.py`
166
172
-**Class**: `FlightControllerInfo`
167
-
-**Purpose**: Stores and derives flight-controller metadata from heartbeat, `AUTOPILOT_VERSION`, and banner data, including capabilities, board information, firmware details, and vehicle type.
173
+
-**Purpose**: Stores and derives flight-controller metadata from heartbeat, `AUTOPILOT_VERSION`, and banner data,
174
+
including capabilities, board information, firmware details, and vehicle type.
168
175
169
176
#### Flight Controller ID Model
170
177
@@ -176,7 +183,8 @@ and the parameter dictionary); the ownership and mutation rules above are the re
-**Purpose**: Lets the user choose or add a connection and provides progress/status feedback.
179
-
-**Key behavior**: `_refresh_ports()` refreshes choices every three seconds while preserving connection history cached from `ProgramSettings`. `reconnect()` persists the user-selected connection string where possible.
186
+
-**Key behavior**: `_refresh_ports()` refreshes choices every three seconds while preserving connection history cached
187
+
from `ProgramSettings`. `reconnect()` persists the user-selected connection string where possible.
180
188
181
189
#### Flight Controller Information UI
182
190
@@ -201,10 +209,12 @@ and the parameter dictionary); the ownership and mutation rules above are the re
201
209
-`FlightController.download_params()` delegates to the parameters manager.
202
210
- When `info.is_mavftp_supported` is true, the manager first tries MAVFTP, including defaults when requested; otherwise it uses MAVLink parameter messages.
203
211
- If MAVFTP fails, it falls back to MAVLink. An incomplete MAVLink download returns no parameter set.
204
-
-`set_param()` only reports send success. A caller needing confirmation follows it with `fetch_param()` or another download.
212
+
-`set_param()` waits briefly for newer firmware's `PARAM_ERROR` rejection response. No response preserves compatibility
213
+
with older firmware, so a caller needing positive confirmation follows it with `fetch_param()` or another download.
205
214
206
215
4.**Command and file operations**
207
-
- The commands manager sends `COMMAND_LONG` messages and waits synchronously for matching `COMMAND_ACK` messages.
216
+
- Command operations that use `send_command_and_wait_ack()` send `COMMAND_LONG` messages and wait synchronously
217
+
for matching `COMMAND_ACK` messages. Batched motor-test commands are sent without per-command acknowledgement waits.
208
218
- Battery status is read from telemetry and briefly cached.
209
219
- The files manager creates a MAVFTP instance for uploads and supported log downloads.
210
220
@@ -224,7 +234,8 @@ and the parameter dictionary); the ownership and mutation rules above are the re
224
234
#### MAVLink Parameter Protocol
225
235
226
236
- Uses `PARAM_REQUEST_LIST`/`PARAM_VALUE` for bulk MAVLink downloads.
227
-
- Uses pymavlink parameter-send support for writes and `PARAM_VALUE` polling for individual reads.
237
+
- Uses pymavlink parameter-send support for writes and locally registers the MAVLink-2 `PARAM_ERROR` decoder required
238
+
by the pinned pymavlink version. It polls `PARAM_VALUE` for individual reads.
228
239
- Validates parameter names and numeric value types locally before writes.
229
240
230
241
#### FTP-over-MAVLink
@@ -238,29 +249,33 @@ and the parameter dictionary); the ownership and mutation rules above are the re
238
249
-**Connection errors**: Return error messages and, for several serial failures, actionable guidance. Pymavlink receives the configured retry/autoreconnect settings.
239
250
-**Timeout errors**: Use operation-specific fixed timeouts and return an error when they expire.
240
251
-**Parameter download errors**: Fall back from MAVFTP to MAVLink; reject incomplete MAVLink downloads.
241
-
-**Parameter write errors**: Validate locally before sending. Read back the parameter when verification is required.
252
+
-**Parameter write errors**: Validate locally before sending and report a matching newer-firmware `PARAM_ERROR`
253
+
rejection. Read back the parameter when positive verification is required or when the firmware provides no rejection response.
242
254
243
255
## Testing Strategy
244
256
245
257
### Test Organization
246
258
247
259
The test suite separates manager/facade tests from SITL coverage:
-`test_backend_flightcontroller.py` exercises facade delegation, lifecycle, commands, parameter workflows, and error
262
+
paths.
250
263
-`test_backend_flightcontroller_business_logic.py` exercises pure calculations and validation functions.
251
-
-`test_backend_flightcontroller_connection.py`, `test_backend_flightcontroller_params.py`, `test_backend_flightcontroller_commands.py`, and `test_backend_flightcontroller_files.py` exercise the specialized managers.
`test_backend_flightcontroller_commands.py`, and `test_backend_flightcontroller_files.py` exercise the specialized managers.
252
266
-`test_backend_flightcontroller_sitl.py` uses a real ArduCopter SITL TCP connection and is marked with both `integration` and `sitl` where applicable.
253
267
254
-
Test names and marker use vary by test; do not treat BDD-style names or integration markers as universal conventions. Avoid recording fixed test counts here because they change as the suite evolves.
268
+
Test names and marker use vary by test; do not treat BDD-style names or integration markers as universal conventions.
269
+
Avoid recording fixed test counts here because they change as the suite evolves.
255
270
256
271
### Running Tests Selectively
257
272
258
273
```bash
259
-
# Run all flight-controller tests
260
-
pytest tests/test_*flightcontroller*.py -v
274
+
# Run all flight-controller tests, including unit-prefixed modules
0 commit comments