ardupilot-methodic-configurator 2.6.1__py3-none-any.whl → 2.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ardupilot-methodic-configurator might be problematic. Click here for more details.
- ardupilot_methodic_configurator/__init__.py +2 -2
- ardupilot_methodic_configurator/__main__.py +25 -1
- ardupilot_methodic_configurator/annotate_params.py +49 -14
- ardupilot_methodic_configurator/argparse_check_range.py +1 -1
- ardupilot_methodic_configurator/backend_filesystem.py +7 -3
- ardupilot_methodic_configurator/backend_filesystem_configuration_steps.py +53 -6
- ardupilot_methodic_configurator/backend_filesystem_json_with_schema.py +3 -3
- ardupilot_methodic_configurator/backend_filesystem_program_settings.py +145 -8
- ardupilot_methodic_configurator/backend_filesystem_vehicle_components.py +3 -3
- ardupilot_methodic_configurator/backend_flightcontroller.py +37 -20
- ardupilot_methodic_configurator/backend_flightcontroller_info.py +1 -1
- ardupilot_methodic_configurator/backend_internet.py +1 -1
- ardupilot_methodic_configurator/backend_mavftp.py +1 -1
- ardupilot_methodic_configurator/battery_cell_voltages.py +1 -1
- ardupilot_methodic_configurator/common_arguments.py +1 -1
- ardupilot_methodic_configurator/configuration_manager.py +450 -115
- ardupilot_methodic_configurator/configuration_steps_ArduCopter.json +6 -4
- ardupilot_methodic_configurator/configuration_steps_ArduPlane.json +3 -1
- ardupilot_methodic_configurator/configuration_steps_Heli.json +3 -1
- ardupilot_methodic_configurator/configuration_steps_Rover.json +3 -1
- ardupilot_methodic_configurator/configuration_steps_strings.py +5 -3
- ardupilot_methodic_configurator/data_model_ardupilot_parameter.py +55 -2
- ardupilot_methodic_configurator/data_model_configuration_step.py +96 -46
- ardupilot_methodic_configurator/data_model_fc_ids.py +16 -7
- ardupilot_methodic_configurator/data_model_motor_test.py +1 -1
- ardupilot_methodic_configurator/data_model_par_dict.py +25 -11
- ardupilot_methodic_configurator/data_model_software_updates.py +1 -1
- ardupilot_methodic_configurator/data_model_template_overview.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_components.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_components_base.py +3 -2
- ardupilot_methodic_configurator/data_model_vehicle_components_display.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_components_import.py +2 -1
- ardupilot_methodic_configurator/data_model_vehicle_components_json_schema.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_components_templates.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_components_validation.py +41 -1
- ardupilot_methodic_configurator/data_model_vehicle_project.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_project_creator.py +1 -1
- ardupilot_methodic_configurator/data_model_vehicle_project_opener.py +1 -1
- ardupilot_methodic_configurator/extract_param_defaults.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_autoresize_combobox.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_base_window.py +5 -1
- ardupilot_methodic_configurator/frontend_tkinter_component_editor.py +55 -29
- ardupilot_methodic_configurator/frontend_tkinter_component_editor_base.py +18 -13
- ardupilot_methodic_configurator/frontend_tkinter_component_template_manager.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_connection_selection.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_directory_selection.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_entry_dynamic.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_flightcontroller_info.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_font.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_motor_test.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_pair_tuple_combobox.py +7 -1
- ardupilot_methodic_configurator/frontend_tkinter_parameter_editor.py +50 -102
- ardupilot_methodic_configurator/frontend_tkinter_parameter_editor_documentation_frame.py +24 -58
- ardupilot_methodic_configurator/frontend_tkinter_parameter_editor_table.py +24 -56
- ardupilot_methodic_configurator/frontend_tkinter_progress_window.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_project_creator.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_project_opener.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_rich_text.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_scroll_frame.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_show.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_software_update.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_stage_progress.py +19 -29
- ardupilot_methodic_configurator/frontend_tkinter_template_overview.py +1 -1
- ardupilot_methodic_configurator/frontend_tkinter_usage_popup_window.py +1 -1
- ardupilot_methodic_configurator/internationalization.py +1 -1
- ardupilot_methodic_configurator/param_pid_adjustment_update.py +43 -39
- ardupilot_methodic_configurator/tempcal_imu.py +1 -1
- ardupilot_methodic_configurator/vehicle_components.py +1 -1
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/AirCar_v1/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Big_Owl/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Chimera7/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/FETtec-5/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/GazeboIrisWithTargetFollow/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X650_LTE/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Hoverit_X11+/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Hoverit_X13/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Marmotte5v2/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/ReadyToSkyZD550/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/05_remote_controller.param +1 -1
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/47_position_controller.param +2 -2
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Tarot_X4/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/X11_plus/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/diatone_taycan_mxc/4.3.8-params/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/diatone_taycan_mxc/4.4.4-params/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/diatone_taycan_mxc/4.5.x-params/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/diatone_taycan_mxc/4.6.x-params/14_logging.param +3 -3
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/empty_4.5.x/10_gnss.param +1 -1
- ardupilot_methodic_configurator/vehicle_templates/ArduCopter/empty_4.6.x/10_gnss.param +1 -1
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/METADATA +11 -6
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/RECORD +106 -106
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/WHEEL +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/entry_points.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSE.md +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/Apache-2.0.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/BSD-3-Clause.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/GPL-3.0-or-later.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/LGPL-3.0-or-later.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/MIT-CMU.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/MIT.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/MPL-2.0.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/LICENSES/PSF-2.0.txt +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/licenses/credits/CREDITS.md +0 -0
- {ardupilot_methodic_configurator-2.6.1.dist-info → ardupilot_methodic_configurator-2.7.0.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""
|
|
4
4
|
A combobox GUI with support for complex lists.
|
|
5
5
|
|
|
6
|
-
This file is part of
|
|
6
|
+
This file is part of ArduPilot Methodic Configurator. https://github.com/ArduPilot/MethodicConfigurator
|
|
7
7
|
|
|
8
8
|
SPDX-FileCopyrightText: 2024-2025 Amilcar do Carmo Lucas <amilcar.lucas@iav.de>
|
|
9
9
|
|
|
@@ -111,6 +111,12 @@ class PairTupleCombobox(ttk.Combobox): # pylint: disable=too-many-ancestors
|
|
|
111
111
|
setup_combobox_mousewheel_handling(self)
|
|
112
112
|
|
|
113
113
|
def set_entries_tuple(self, list_pair_tuple: list[tuple[str, str]], selected_element: Union[None, str]) -> None:
|
|
114
|
+
# Clear existing entries before setting new ones
|
|
115
|
+
self.list_keys.clear()
|
|
116
|
+
self.list_shows.clear()
|
|
117
|
+
self.append_entries_tuple(list_pair_tuple, selected_element)
|
|
118
|
+
|
|
119
|
+
def append_entries_tuple(self, list_pair_tuple: list[tuple[str, str]], selected_element: Union[None, str]) -> None:
|
|
114
120
|
if isinstance(list_pair_tuple, list):
|
|
115
121
|
for tpl in list_pair_tuple:
|
|
116
122
|
self.list_keys.append(tpl[0])
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"""
|
|
4
4
|
Parameter editor GUI.
|
|
5
5
|
|
|
6
|
-
This file is part of
|
|
6
|
+
This file is part of ArduPilot Methodic Configurator. https://github.com/ArduPilot/MethodicConfigurator
|
|
7
7
|
|
|
8
8
|
SPDX-FileCopyrightText: 2024-2025 Amilcar do Carmo Lucas <amilcar.lucas@iav.de>
|
|
9
9
|
|
|
@@ -19,7 +19,6 @@ from argparse import ArgumentParser, Namespace
|
|
|
19
19
|
from logging import basicConfig as logging_basicConfig
|
|
20
20
|
from logging import error as logging_error
|
|
21
21
|
from logging import getLevelName as logging_getLevelName
|
|
22
|
-
from logging import info as logging_info
|
|
23
22
|
from logging import warning as logging_warning
|
|
24
23
|
from tkinter import filedialog, messagebox, ttk
|
|
25
24
|
from typing import Literal, Optional, Union
|
|
@@ -36,6 +35,7 @@ from ardupilot_methodic_configurator.configuration_manager import ConfigurationM
|
|
|
36
35
|
from ardupilot_methodic_configurator.frontend_tkinter_autoresize_combobox import AutoResizeCombobox
|
|
37
36
|
from ardupilot_methodic_configurator.frontend_tkinter_base_window import (
|
|
38
37
|
BaseWindow,
|
|
38
|
+
ask_retry_cancel_popup,
|
|
39
39
|
ask_yesno_popup,
|
|
40
40
|
show_error_popup,
|
|
41
41
|
show_info_popup,
|
|
@@ -156,10 +156,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
156
156
|
def __init__(self, configuration_manager: ConfigurationManager) -> None:
|
|
157
157
|
super().__init__()
|
|
158
158
|
self.configuration_manager = configuration_manager
|
|
159
|
-
# Maintain backward compatibility with existing code
|
|
160
|
-
self.local_filesystem = configuration_manager.filesystem
|
|
161
159
|
|
|
162
|
-
self.at_least_one_changed_parameter_written = False
|
|
163
160
|
self.file_selection_combobox: AutoResizeCombobox
|
|
164
161
|
self.show_only_differences: tk.BooleanVar
|
|
165
162
|
self.annotate_params_into_files: tk.BooleanVar
|
|
@@ -193,20 +190,15 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
193
190
|
|
|
194
191
|
self.__create_conf_widgets(__version__)
|
|
195
192
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
last_step_nr = int(last_step_filename[:2]) + 1 if len(last_step_filename) >= 2 else 1
|
|
193
|
+
last_step_nr = self.configuration_manager.get_last_configuration_step_number()
|
|
194
|
+
if last_step_nr is not None:
|
|
195
|
+
phases = self.configuration_manager.get_sorted_phases_with_end_and_weight(last_step_nr)
|
|
200
196
|
|
|
201
|
-
self.stage_progress_bar = StageProgressBar(
|
|
202
|
-
self.main_frame, self.local_filesystem.configuration_phases, last_step_nr, self.gui_complexity
|
|
203
|
-
)
|
|
197
|
+
self.stage_progress_bar = StageProgressBar(self.main_frame, phases, last_step_nr, self.gui_complexity)
|
|
204
198
|
self.stage_progress_bar.pack(side=tk.TOP, fill="x", expand=False, pady=(2, 2), padx=(4, 4))
|
|
205
199
|
|
|
206
200
|
# Create a DocumentationFrame object for the Documentation Content
|
|
207
|
-
self.documentation_frame = DocumentationFrame(
|
|
208
|
-
self.main_frame, self.local_filesystem, self.configuration_manager.current_file
|
|
209
|
-
)
|
|
201
|
+
self.documentation_frame = DocumentationFrame(self.main_frame, self.configuration_manager)
|
|
210
202
|
self.documentation_frame.documentation_frame.pack(side=tk.TOP, fill="x", expand=False, pady=(2, 2), padx=(4, 4))
|
|
211
203
|
|
|
212
204
|
self.__create_parameter_area_widgets()
|
|
@@ -231,7 +223,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
231
223
|
directory_selection_frame = VehicleDirectorySelectionWidgets(
|
|
232
224
|
self,
|
|
233
225
|
config_subframe,
|
|
234
|
-
self.
|
|
226
|
+
self.configuration_manager.get_vehicle_directory(),
|
|
235
227
|
destroy_parent_on_open=False,
|
|
236
228
|
)
|
|
237
229
|
if self.gui_complexity != "simple":
|
|
@@ -250,7 +242,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
250
242
|
# Create Combobox for intermediate parameter file selection
|
|
251
243
|
self.file_selection_combobox = AutoResizeCombobox(
|
|
252
244
|
file_selection_frame,
|
|
253
|
-
|
|
245
|
+
self.configuration_manager.parameter_files(),
|
|
254
246
|
self.configuration_manager.current_file,
|
|
255
247
|
_(
|
|
256
248
|
"Select the intermediate parameter file from the list of available"
|
|
@@ -326,7 +318,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
326
318
|
|
|
327
319
|
# Create a Scrollable parameter editor table
|
|
328
320
|
self.parameter_editor_table = ParameterEditorTable(self.main_frame, self.configuration_manager, self)
|
|
329
|
-
self.repopulate_parameter_table()
|
|
321
|
+
self.repopulate_parameter_table(regenerate_from_disk=True)
|
|
330
322
|
self.parameter_editor_table.pack(side="top", fill="both", expand=True)
|
|
331
323
|
|
|
332
324
|
# Create a frame for the buttons
|
|
@@ -354,7 +346,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
354
346
|
annotate_params_checkbox = ttk.Checkbutton(
|
|
355
347
|
checkboxes_frame,
|
|
356
348
|
text=_("Annotate docs into .param files"),
|
|
357
|
-
state="normal" if self.
|
|
349
|
+
state="normal" if self.configuration_manager.parameter_documentation_available() else "disabled",
|
|
358
350
|
variable=self.annotate_params_into_files,
|
|
359
351
|
command=lambda: ProgramSettings.set_setting(
|
|
360
352
|
"annotate_docs_into_param_files", self.annotate_params_into_files.get()
|
|
@@ -419,7 +411,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
419
411
|
state=(
|
|
420
412
|
"normal"
|
|
421
413
|
if self.gui_complexity != "simple"
|
|
422
|
-
or self.configuration_manager.is_configuration_step_optional(
|
|
414
|
+
or self.configuration_manager.is_configuration_step_optional()
|
|
423
415
|
or not self.configuration_manager.is_fc_connected
|
|
424
416
|
else "disabled"
|
|
425
417
|
)
|
|
@@ -505,7 +497,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
505
497
|
|
|
506
498
|
try:
|
|
507
499
|
# Inject GUI callbacks into business logic workflow
|
|
508
|
-
|
|
500
|
+
_success = self.configuration_manager.handle_imu_temperature_calibration_workflow(
|
|
509
501
|
selected_file,
|
|
510
502
|
ask_user_confirmation=ask_yesno_popup,
|
|
511
503
|
select_file=select_file,
|
|
@@ -514,10 +506,6 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
514
506
|
progress_callback=self.tempcal_imu_progress_window.update_progress_bar_300_pct,
|
|
515
507
|
)
|
|
516
508
|
|
|
517
|
-
if success:
|
|
518
|
-
# Force writing doc annotations to file
|
|
519
|
-
self.parameter_editor_table.set_at_least_one_param_edited(True)
|
|
520
|
-
|
|
521
509
|
finally:
|
|
522
510
|
self.tempcal_imu_progress_window.destroy()
|
|
523
511
|
|
|
@@ -607,9 +595,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
607
595
|
response = result[-1] if len(result) > 1 else None
|
|
608
596
|
|
|
609
597
|
if response is True: # Yes option
|
|
610
|
-
|
|
611
|
-
if params_copied:
|
|
612
|
-
self.parameter_editor_table.set_at_least_one_param_edited(True)
|
|
598
|
+
_params_copied = self.configuration_manager.copy_fc_values_to_file(selected_file, relevant_fc_params)
|
|
613
599
|
elif response is None: # Close option
|
|
614
600
|
sys.exit(0)
|
|
615
601
|
# If response is False (No option), do nothing and continue
|
|
@@ -657,22 +643,22 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
657
643
|
self.__do_tempcal_imu(selected_file)
|
|
658
644
|
# open the documentation of the next step in the browser,
|
|
659
645
|
# before giving the user the option to close the SW in the __should_copy_fc_values_to_file method
|
|
660
|
-
self.documentation_frame.
|
|
646
|
+
if self.documentation_frame.get_auto_open_documentation_in_browser() or self.gui_complexity == "simple":
|
|
647
|
+
self.configuration_manager.open_documentation_in_browser(selected_file)
|
|
661
648
|
self.__should_copy_fc_values_to_file(selected_file)
|
|
662
649
|
selected_file = self.__should_jump_to_file(selected_file)
|
|
663
650
|
self.__should_download_file_from_url(selected_file)
|
|
664
651
|
self.__should_upload_file_to_fc(selected_file)
|
|
665
652
|
|
|
666
|
-
#
|
|
653
|
+
# current_file might have been changed by jump, so update again
|
|
667
654
|
self.configuration_manager.current_file = selected_file
|
|
668
|
-
self.
|
|
669
|
-
self.documentation_frame.
|
|
670
|
-
self.
|
|
671
|
-
self.repopulate_parameter_table()
|
|
655
|
+
self.documentation_frame.refresh_documentation_labels()
|
|
656
|
+
self.documentation_frame.update_why_why_now_tooltip()
|
|
657
|
+
self.repopulate_parameter_table(regenerate_from_disk=True)
|
|
672
658
|
self._update_skip_button_state()
|
|
673
659
|
|
|
674
660
|
def _update_progress_bar_from_file(self, selected_file: str) -> None:
|
|
675
|
-
if self.
|
|
661
|
+
if self.configuration_manager.configuration_phases():
|
|
676
662
|
try:
|
|
677
663
|
step_nr = int(selected_file[:2])
|
|
678
664
|
self.stage_progress_bar.update_progress(step_nr)
|
|
@@ -690,37 +676,14 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
690
676
|
if not redownload:
|
|
691
677
|
self.on_param_file_combobox_change(None, forced=True) # the initial param read will trigger a table update
|
|
692
678
|
|
|
693
|
-
def repopulate_parameter_table(self) -> None:
|
|
679
|
+
def repopulate_parameter_table(self, regenerate_from_disk: bool) -> None:
|
|
694
680
|
if not self.configuration_manager.current_file:
|
|
695
681
|
return # no file was yet selected, so skip it
|
|
696
682
|
# Re-populate the table with the new parameters
|
|
697
|
-
self.parameter_editor_table.repopulate(self.show_only_differences.get(), self.gui_complexity)
|
|
683
|
+
self.parameter_editor_table.repopulate(self.show_only_differences.get(), self.gui_complexity, regenerate_from_disk)
|
|
698
684
|
|
|
699
685
|
def on_show_only_changed_checkbox_change(self) -> None:
|
|
700
|
-
self.repopulate_parameter_table()
|
|
701
|
-
|
|
702
|
-
def upload_params_that_require_reset(self, selected_params: dict) -> None:
|
|
703
|
-
"""
|
|
704
|
-
Write only the selected parameters to the flight controller that require a reset.
|
|
705
|
-
|
|
706
|
-
After the reset, the other parameters that do not require a reset must still be written to the flight controller.
|
|
707
|
-
"""
|
|
708
|
-
self.reset_progress_window = ProgressWindow(
|
|
709
|
-
self.root,
|
|
710
|
-
_("Resetting Flight Controller"),
|
|
711
|
-
_("Waiting for {} of {} seconds"),
|
|
712
|
-
only_show_when_update_progress_called=True,
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
if self.configuration_manager.upload_parameters_that_require_reset_workflow(
|
|
716
|
-
selected_params,
|
|
717
|
-
ask_confirmation=ask_yesno_popup,
|
|
718
|
-
show_error=show_error_popup,
|
|
719
|
-
progress_callback=self.reset_progress_window.update_progress_bar,
|
|
720
|
-
):
|
|
721
|
-
self.at_least_one_changed_parameter_written = True
|
|
722
|
-
|
|
723
|
-
self.reset_progress_window.destroy() # for the case that we are doing a test and there is no real FC connected
|
|
686
|
+
self.repopulate_parameter_table(regenerate_from_disk=False)
|
|
724
687
|
|
|
725
688
|
def on_upload_selected_click(self) -> None:
|
|
726
689
|
self.write_changes_to_intermediate_parameter_file()
|
|
@@ -741,41 +704,31 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
741
704
|
|
|
742
705
|
# This function can recurse multiple times if there is an upload error
|
|
743
706
|
def upload_selected_params(self, selected_params: dict) -> None:
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
707
|
+
# Create progress windows
|
|
708
|
+
self.reset_progress_window = ProgressWindow(
|
|
709
|
+
self.root,
|
|
710
|
+
_("Resetting Flight Controller"),
|
|
711
|
+
_("Waiting for {} of {} seconds"),
|
|
712
|
+
only_show_when_update_progress_called=True,
|
|
748
713
|
)
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
nr_changed = self.configuration_manager.upload_selected_parameters_workflow(
|
|
754
|
-
selected_params, show_error=show_error_popup
|
|
714
|
+
self.param_download_progress_window = ProgressWindow(
|
|
715
|
+
self.root,
|
|
716
|
+
_("Re-downloading FC parameters"),
|
|
717
|
+
_("Downloaded {} of {} parameters"),
|
|
755
718
|
)
|
|
756
719
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
_("Failed to upload the following parameters to the flight controller:\n")
|
|
770
|
-
+ f"{(', ').join(param_upload_error)}",
|
|
771
|
-
):
|
|
772
|
-
self.upload_selected_params(selected_params)
|
|
773
|
-
else:
|
|
774
|
-
logging_info(_("All parameters uploaded to the flight controller successfully"))
|
|
775
|
-
|
|
776
|
-
self.configuration_manager.export_fc_params_missing_or_different()
|
|
777
|
-
|
|
778
|
-
self.local_filesystem.write_last_uploaded_filename(self.configuration_manager.current_file)
|
|
720
|
+
try:
|
|
721
|
+
self.configuration_manager.upload_selected_params_workflow(
|
|
722
|
+
selected_params,
|
|
723
|
+
ask_confirmation=ask_yesno_popup,
|
|
724
|
+
ask_retry_cancel=ask_retry_cancel_popup,
|
|
725
|
+
show_error=show_error_popup,
|
|
726
|
+
progress_callback_for_reset=self.reset_progress_window.update_progress_bar,
|
|
727
|
+
progress_callback_for_download=self.param_download_progress_window.update_progress_bar,
|
|
728
|
+
)
|
|
729
|
+
finally:
|
|
730
|
+
self.reset_progress_window.destroy()
|
|
731
|
+
self.param_download_progress_window.destroy()
|
|
779
732
|
|
|
780
733
|
def on_download_last_flight_log_click(self) -> None:
|
|
781
734
|
"""Handle the download last flight log button click."""
|
|
@@ -811,7 +764,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
811
764
|
skip_button_state = (
|
|
812
765
|
"normal"
|
|
813
766
|
if self.gui_complexity != "simple"
|
|
814
|
-
or self.configuration_manager.is_configuration_step_optional(
|
|
767
|
+
or self.configuration_manager.is_configuration_step_optional()
|
|
815
768
|
or not self.configuration_manager.is_fc_connected
|
|
816
769
|
else "disabled"
|
|
817
770
|
)
|
|
@@ -821,7 +774,7 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
821
774
|
self.write_changes_to_intermediate_parameter_file()
|
|
822
775
|
|
|
823
776
|
# Use ConfigurationManager to get the next non-optional file
|
|
824
|
-
next_file = self.configuration_manager.get_next_non_optional_file(
|
|
777
|
+
next_file = self.configuration_manager.get_next_non_optional_file()
|
|
825
778
|
|
|
826
779
|
if next_file is None:
|
|
827
780
|
# No more files to process, write summary and close
|
|
@@ -844,19 +797,14 @@ class ParameterEditorWindow(BaseWindow): # pylint: disable=too-many-instance-at
|
|
|
844
797
|
# the parameter metadata might have changed, or not be present in the file.
|
|
845
798
|
# In that situation, avoid asking multiple times to write the file, by checking the time last asked
|
|
846
799
|
# But only if self.annotate_params_into_files.get()
|
|
847
|
-
if self.
|
|
800
|
+
if self.configuration_manager.has_unsaved_changes() or (
|
|
848
801
|
self.annotate_params_into_files.get() and elapsed_since_last_ask > 1.0
|
|
849
802
|
):
|
|
850
803
|
msg = _("Do you want to write the changes to the {current_filename} file?").format(
|
|
851
804
|
current_filename=self.configuration_manager.current_file
|
|
852
805
|
)
|
|
853
806
|
if messagebox.askyesno(_("One or more parameters have been edited"), msg.format(**locals())):
|
|
854
|
-
self.
|
|
855
|
-
self.local_filesystem.file_parameters[self.configuration_manager.current_file],
|
|
856
|
-
self.configuration_manager.current_file,
|
|
857
|
-
annotate_doc=self.annotate_params_into_files.get(),
|
|
858
|
-
)
|
|
859
|
-
self.parameter_editor_table.set_at_least_one_param_edited(False)
|
|
807
|
+
self.configuration_manager.export_current_file(annotate_doc=self.annotate_params_into_files.get())
|
|
860
808
|
self.last_time_asked_to_save = time.time()
|
|
861
809
|
|
|
862
810
|
def close_connection_and_quit(self) -> None:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
The documentation frame containing the documentation for the current configuration step.
|
|
3
3
|
|
|
4
|
-
This file is part of
|
|
4
|
+
This file is part of ArduPilot Methodic Configurator. https://github.com/ArduPilot/MethodicConfigurator
|
|
5
5
|
|
|
6
6
|
SPDX-FileCopyrightText: 2024-2025 Amilcar do Carmo Lucas <amilcar.lucas@iav.de>
|
|
7
7
|
|
|
@@ -11,11 +11,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
11
11
|
import tkinter as tk
|
|
12
12
|
from platform import system as platform_system
|
|
13
13
|
from tkinter import ttk
|
|
14
|
-
from webbrowser import open as webbrowser_open # to open the
|
|
14
|
+
from webbrowser import open as webbrowser_open # to open the web documentation
|
|
15
15
|
|
|
16
16
|
from ardupilot_methodic_configurator import _
|
|
17
|
-
from ardupilot_methodic_configurator.backend_filesystem import LocalFilesystem
|
|
18
17
|
from ardupilot_methodic_configurator.backend_filesystem_program_settings import ProgramSettings
|
|
18
|
+
from ardupilot_methodic_configurator.configuration_manager import ConfigurationManager
|
|
19
19
|
from ardupilot_methodic_configurator.frontend_tkinter_rich_text import get_widget_font_family_and_size
|
|
20
20
|
from ardupilot_methodic_configurator.frontend_tkinter_show import show_tooltip
|
|
21
21
|
|
|
@@ -49,16 +49,16 @@ class DocumentationFrame:
|
|
|
49
49
|
),
|
|
50
50
|
)
|
|
51
51
|
|
|
52
|
-
def __init__(self, root: tk.Widget,
|
|
52
|
+
def __init__(self, root: tk.Widget, configuration_manager: ConfigurationManager) -> None:
|
|
53
53
|
self.root = root
|
|
54
|
-
self.
|
|
54
|
+
self.configuration_manager = configuration_manager
|
|
55
55
|
self.documentation_frame: ttk.LabelFrame
|
|
56
56
|
self.documentation_labels: dict[str, ttk.Label] = {}
|
|
57
57
|
self.mandatory_level: ttk.Progressbar
|
|
58
58
|
self.auto_open_var = tk.BooleanVar(value=bool(ProgramSettings.get_setting("auto_open_doc_in_browser")))
|
|
59
|
-
self._create_documentation_frame(
|
|
59
|
+
self._create_documentation_frame()
|
|
60
60
|
|
|
61
|
-
def _create_documentation_frame(self
|
|
61
|
+
def _create_documentation_frame(self) -> None:
|
|
62
62
|
self.documentation_frame = ttk.LabelFrame(self.root, text=_("Documentation"))
|
|
63
63
|
|
|
64
64
|
# Create a grid structure within the documentation_frame
|
|
@@ -86,8 +86,8 @@ class DocumentationFrame:
|
|
|
86
86
|
documentation_grid.columnconfigure(1, weight=1)
|
|
87
87
|
|
|
88
88
|
# Dynamically update the documentation text and URL links
|
|
89
|
-
self.refresh_documentation_labels(
|
|
90
|
-
self.update_why_why_now_tooltip(
|
|
89
|
+
self.refresh_documentation_labels()
|
|
90
|
+
self.update_why_why_now_tooltip()
|
|
91
91
|
|
|
92
92
|
def _create_bottom_row(self, documentation_grid: ttk.Frame, row: int) -> None:
|
|
93
93
|
bottom_frame = ttk.Frame(documentation_grid)
|
|
@@ -111,52 +111,28 @@ class DocumentationFrame:
|
|
|
111
111
|
)
|
|
112
112
|
auto_open_checkbox.pack(side=tk.LEFT, expand=False)
|
|
113
113
|
|
|
114
|
-
def update_why_why_now_tooltip(self
|
|
115
|
-
|
|
116
|
-
why_now_tooltip_text = self.local_filesystem.get_seq_tooltip_text(current_file, "why_now")
|
|
117
|
-
tooltip_text = ""
|
|
118
|
-
if why_tooltip_text:
|
|
119
|
-
tooltip_text += _("Why: ") + _(why_tooltip_text) + "\n"
|
|
120
|
-
if why_now_tooltip_text:
|
|
121
|
-
tooltip_text += _("Why now: ") + _(why_now_tooltip_text)
|
|
114
|
+
def update_why_why_now_tooltip(self) -> None:
|
|
115
|
+
tooltip_text = self.configuration_manager.get_why_why_now_tooltip()
|
|
122
116
|
if tooltip_text:
|
|
123
117
|
show_tooltip(self.documentation_frame, tooltip_text, position_below=False)
|
|
124
118
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
_wiki_text, wiki_url = self.local_filesystem.get_documentation_text_and_url(current_file, "wiki")
|
|
128
|
-
_external_tool_text, external_tool_url = self.local_filesystem.get_documentation_text_and_url(
|
|
129
|
-
current_file, "external_tool"
|
|
130
|
-
)
|
|
119
|
+
def get_auto_open_documentation_in_browser(self) -> bool:
|
|
120
|
+
return self.auto_open_var.get()
|
|
131
121
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
webbrowser_open(url=wiki_url, new=0, autoraise=False)
|
|
135
|
-
if external_tool_url:
|
|
136
|
-
webbrowser_open(url=external_tool_url, new=0, autoraise=False)
|
|
137
|
-
if blog_url:
|
|
138
|
-
webbrowser_open(url=blog_url, new=0, autoraise=True)
|
|
139
|
-
|
|
140
|
-
def refresh_documentation_labels(self, current_file: str) -> None:
|
|
141
|
-
if current_file:
|
|
142
|
-
title = _("{current_file} Documentation")
|
|
143
|
-
frame_title = title.format(**locals())
|
|
144
|
-
else:
|
|
145
|
-
frame_title = _("Documentation")
|
|
122
|
+
def refresh_documentation_labels(self) -> None:
|
|
123
|
+
frame_title = self.configuration_manager.get_documentation_frame_title()
|
|
146
124
|
self.documentation_frame.config(text=frame_title)
|
|
147
125
|
|
|
148
|
-
blog_text, blog_url = self.
|
|
126
|
+
blog_text, blog_url = self.configuration_manager.get_documentation_text_and_url("blog")
|
|
149
127
|
self._refresh_documentation_label(self.BLOG_LABEL, _(blog_text) if blog_text else "", blog_url)
|
|
150
|
-
wiki_text, wiki_url = self.
|
|
128
|
+
wiki_text, wiki_url = self.configuration_manager.get_documentation_text_and_url("wiki")
|
|
151
129
|
self._refresh_documentation_label(self.WIKI_LABEL, _(wiki_text) if wiki_text else "", wiki_url)
|
|
152
|
-
external_tool_text, external_tool_url = self.
|
|
153
|
-
current_file, "external_tool"
|
|
154
|
-
)
|
|
130
|
+
external_tool_text, external_tool_url = self.configuration_manager.get_documentation_text_and_url("external_tool")
|
|
155
131
|
self._refresh_documentation_label(
|
|
156
132
|
self.EXTERNAL_TOOL_LABEL, _(external_tool_text) if external_tool_text else "", external_tool_url
|
|
157
133
|
)
|
|
158
|
-
mandatory_text, _mandatory_url = self.
|
|
159
|
-
self._refresh_mandatory_level(
|
|
134
|
+
mandatory_text, _mandatory_url = self.configuration_manager.get_documentation_text_and_url("mandatory")
|
|
135
|
+
self._refresh_mandatory_level(mandatory_text)
|
|
160
136
|
|
|
161
137
|
def _refresh_documentation_label(self, label_key: str, text: str, url: str, url_expected: bool = True) -> None:
|
|
162
138
|
label = self.documentation_labels[label_key]
|
|
@@ -175,17 +151,7 @@ class DocumentationFrame:
|
|
|
175
151
|
if url_expected:
|
|
176
152
|
show_tooltip(label, _("Documentation URL not available"))
|
|
177
153
|
|
|
178
|
-
def _refresh_mandatory_level(self,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
percentage = int("".join([c for c in text[:3] if c.isdigit()]))
|
|
183
|
-
if 0 <= percentage <= 100:
|
|
184
|
-
self.mandatory_level.config(value=percentage)
|
|
185
|
-
tooltip = _("This configuration step ({current_file} intermediate parameter file) is {percentage}% mandatory")
|
|
186
|
-
else:
|
|
187
|
-
raise ValueError
|
|
188
|
-
except ValueError:
|
|
189
|
-
self.mandatory_level.config(value=0)
|
|
190
|
-
tooltip = _("Mandatory level not available for this configuration step ({current_file})")
|
|
191
|
-
show_tooltip(self.mandatory_level, tooltip.format(**locals()))
|
|
154
|
+
def _refresh_mandatory_level(self, text: str) -> None:
|
|
155
|
+
percentage, tooltip = self.configuration_manager.parse_mandatory_level_percentage(text)
|
|
156
|
+
self.mandatory_level.config(value=percentage)
|
|
157
|
+
show_tooltip(self.mandatory_level, tooltip)
|