Skip to content

Commit 7ad78c3

Browse files
committed
refactor(flightcontroller): decompose FlightController into specialized managers using delegation pattern
Splits monolithic 820-line FlightController class into focused component managers: - FlightControllerConnection: port discovery, connection lifecycle, heartbeat detection - FlightControllerParams: parameter download, upload, querying via MAVLink/MAVFTP - FlightControllerCommands: motor tests, battery status, command execution - FlightControllerFiles: file upload/download via MAVFTP Introduces protocol-based interfaces for dependency injection and testing. Connection manager is single source of truth for master, comport, and info state. Params manager is single source of truth for fc_parameters state. Documents error handling standards and testing patterns in ARCHITECTURE.md.
1 parent 124616d commit 7ad78c3

13 files changed

Lines changed: 3089 additions & 1271 deletions

ARCHITECTURE.md

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,13 @@ Each sub-application has detailed architecture documentation covering requiremen
7676
2. **[Flight Controller Communication](ARCHITECTURE_2_flight_controller_communication.md)** - Establishes FC connection, downloads parameters and metadata
7777
- [`frontend_tkinter_connection_selection.py`](ardupilot_methodic_configurator/frontend_tkinter_connection_selection.py)
7878
- [`frontend_tkinter_flightcontroller_info.py`](ardupilot_methodic_configurator/frontend_tkinter_flightcontroller_info.py)
79-
- [`backend_flightcontroller.py`](ardupilot_methodic_configurator/backend_flightcontroller.py)
79+
- [`backend_flightcontroller.py`](ardupilot_methodic_configurator/backend_flightcontroller.py) - Main facade class using delegation pattern
80+
- [`backend_flightcontroller_connection.py`](ardupilot_methodic_configurator/backend_flightcontroller_connection.py) - Connection management
81+
- [`backend_flightcontroller_params.py`](ardupilot_methodic_configurator/backend_flightcontroller_params.py) - Parameter operations
82+
- [`backend_flightcontroller_commands.py`](ardupilot_methodic_configurator/backend_flightcontroller_commands.py) - Command execution
83+
- [`backend_flightcontroller_files.py`](ardupilot_methodic_configurator/backend_flightcontroller_files.py) - File operations
84+
- [`data_model_flightcontroller_info.py`](ardupilot_methodic_configurator/data_model_flightcontroller_info.py) - FC information
85+
- [`backend_flightcontroller_protocols.py`](ardupilot_methodic_configurator/backend_flightcontroller_protocols.py) - Protocol definitions
8086
- [`backend_mavftp.py`](ardupilot_methodic_configurator/backend_mavftp.py)
8187

8288
3. **[Directory and Project Selection](ARCHITECTURE_3_directory_selection.md)** - Creates new projects or opens existing ones
@@ -154,9 +160,63 @@ All applications use one or more of the following shared libraries:
154160
4. [`backend_filesystem_program_settings.py`](ardupilot_methodic_configurator/backend_filesystem_program_settings.py)
155161
1. the internet backend communicates with the internet
156162
1. [`backend_internet.py`](ardupilot_methodic_configurator/backend_internet.py)
157-
1. the flight controller backend communicates with the flight controller
158-
1. [`backend_flightcontroller.py`](ardupilot_methodic_configurator/backend_flightcontroller.py)
159-
2. [`backend_mavftp.py`](ardupilot_methodic_configurator/backend_mavftp.py)
163+
1. the flight controller backend communicates with the flight controller using a **delegation pattern** with specialized managers:
164+
1. [`backend_flightcontroller.py`](ardupilot_methodic_configurator/backend_flightcontroller.py) -
165+
Main facade class that delegates to specialized managers
166+
2. [`backend_flightcontroller_connection.py`](ardupilot_methodic_configurator/backend_flightcontroller_connection.py) -
167+
Handles connection establishment, port discovery, and heartbeat detection
168+
3. [`backend_flightcontroller_params.py`](ardupilot_methodic_configurator/backend_flightcontroller_params.py) -
169+
Manages parameter download, upload, and querying
170+
4. [`backend_flightcontroller_commands.py`](ardupilot_methodic_configurator/backend_flightcontroller_commands.py) -
171+
Executes MAVLink commands (motor tests, battery status, etc.)
172+
5. [`backend_flightcontroller_files.py`](ardupilot_methodic_configurator/backend_flightcontroller_files.py) -
173+
Handles file upload/download via MAVFTP
174+
6. [`data_model_flightcontroller_info.py`](ardupilot_methodic_configurator/data_model_flightcontroller_info.py) -
175+
Stores flight controller metadata and capabilities
176+
7. [`backend_flightcontroller_protocols.py`](ardupilot_methodic_configurator/backend_flightcontroller_protocols.py) -
177+
Protocol definitions for dependency injection and testing
178+
8. [`backend_mavftp.py`](ardupilot_methodic_configurator/backend_mavftp.py) - MAVFTP protocol implementation
179+
180+
**Flight Controller Backend Architecture:**
181+
- The `FlightController` class acts as a facade, delegating operations to specialized managers
182+
- Each manager handles a specific concern (connection, parameters, commands, files)
183+
- Managers can reference each other (e.g., params manager holds reference to connection manager)
184+
- Protocol definitions enable dependency injection for testing
185+
- Connection manager is the source of truth for connection state (`master`, `comport`, `info`)
186+
- Other managers query connection manager for current state rather than caching it
187+
188+
**Error Handling Standards:**
189+
190+
To maintain consistency across the flight controller backend, the following error handling patterns are used:
191+
192+
1. **Connection and I/O Operations** - Return `str` (empty string on success, error message on failure):
193+
- `connect()`, `disconnect()`, `register_and_try_connect()`
194+
- Rationale: Allows user-friendly error messages to be displayed directly
195+
196+
2. **Command Operations** - Return `tuple[bool, str]` (success flag, error message):
197+
- `test_motor()`, `test_all_motors()`, `reset_all_parameters_to_default()`
198+
- Rationale: Separates success/failure from error details for better control flow
199+
200+
3. **Query Operations** - Return `Optional[T]` or raise exceptions:
201+
- `fetch_param()` - raises `TimeoutError` on timeout
202+
- `get_battery_status()` - returns `tuple[Optional[tuple[float, float]], str]`
203+
- Rationale: Distinguishes between "not found" (None) and "error" (exception)
204+
205+
4. **Bulk Operations** - Return data structures or tuples:
206+
- `download_params()` - returns `tuple[dict[str, float], ParDict]`
207+
- Rationale: Success implied by returned data, errors logged but not returned
208+
209+
**Testing Hacks and Violations:**
210+
211+
The following methods exist for testing purposes only and violate architectural principles:
212+
213+
- `FlightController.set_master_for_testing()` - Directly mutates connection manager's internal state,
214+
violating the principle that connection manager should be the sole mutator of connection state.
215+
**Never use in production code.**
216+
217+
- Test parameter loading via `device="test"` in `backend_flightcontroller_params.py` - Bypasses normal
218+
parameter download flow to load from local file. **Marked with FIXME for future removal.**
219+
160220
1. the tkinter frontend, which is the GUI the user interacts with
161221
1. [`frontend_tkinter_autoresize_combobox.py`](ardupilot_methodic_configurator/frontend_tkinter_autoresize_combobox.py)
162222
1. [`frontend_tkinter_base_window.py`](ardupilot_methodic_configurator/frontend_tkinter_base_window.py)

0 commit comments

Comments
 (0)