Skip to content

Commit 47ae7f1

Browse files
refactor: added basic checks in json
Signed-off-by: Omkar Sarkar <omkarsarkar24@gmail.com>
1 parent 75352a8 commit 47ae7f1

4 files changed

Lines changed: 66 additions & 98 deletions

File tree

REUSE.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ SPDX-FileCopyrightText = "2024-2026 Amilcar Lucas"
3131
SPDX-License-Identifier = "GPL-3.0-or-later"
3232

3333
[[annotations]]
34-
path = ["ardupilot_methodic_configurator/images/*.png", "ardupilot_methodic_configurator/*.json", "ardupilot_methodic_configurator/log_analysis/*.json"]
34+
path = ["ardupilot_methodic_configurator/images/*.png", "ardupilot_methodic_configurator/*.json"]
3535
SPDX-FileCopyrightText = "2024-2026 Amilcar Lucas"
3636
SPDX-License-Identifier = "GPL-3.0-or-later"
3737

ardupilot_methodic_configurator/configuration_steps_ArduCopter.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,12 @@
260260
"SERVO_FTW_POLES": {}
261261
},
262262
"rename_connection": "vehicle_components['ESC']['ESC->FC Telemetry']['Type']",
263-
"old_filenames": ["07_esc.param"]
263+
"old_filenames": ["07_esc.param"],
264+
"related_bin_messages": {
265+
"ESC": { "name": "ESC telemetry", "required": true },
266+
"ESCX": { "name": "ESC extended status", "required": false },
267+
"EDT2": { "name": "Extended DShot telemetry", "required": false }
268+
}
264269
},
265270
"10_battery_monitor.param": {
266271
"why": "The battery monitor must be configured to match the hardware connection type so that the autopilot correctly reads battery voltage and current",
@@ -288,6 +293,10 @@
288293
"plugin": {
289294
"name": "battery_monitor",
290295
"placement": "left"
296+
},
297+
"related_bin_messages": {
298+
"BAT": {"name": "Battery", "required": true},
299+
"BCL": {"name": "Battery cell voltages", "required": false }
291300
}
292301
},
293302
"11_battery.param": {
@@ -343,7 +352,18 @@
343352
"GPS1_TYPE": { "if": "Version(vehicle_components['Flight Controller']['Firmware']['Version'].split(' ')[0]) >= Version('4.6')","New Value": "vehicle_components['GNSS Receiver']['FC Connection']['Protocol']", "Change Reason": "Defined in component editor" }
344353
},
345354
"rename_connection": "vehicle_components['GNSS Receiver']['FC Connection']['Type']",
346-
"old_filenames": ["10_gnss.param"]
355+
"old_filenames": ["10_gnss.param"],
356+
"related_bin_messages": {
357+
"GPS": {
358+
"name": "GPS",
359+
"required": true
360+
},
361+
"GPA": {
362+
"name": "GPS accuracy",
363+
"required": false
364+
}
365+
366+
}
347367
},
348368
"13_initial_atc.param": {
349369
"why": "Propeller size has a big influence on the vehicle dynamics, this adapts the attitude controller response to it",

ardupilot_methodic_configurator/log_analysis/analysis_plugins.json

Lines changed: 0 additions & 62 deletions
This file was deleted.

ardupilot_methodic_configurator/log_analysis/backend_log_quality_check.py

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""
22
ArduPilot log quality checker.
33
4-
Validates that the messages required by each analysis plugin, and configuration are present,
5-
and that logged record matches its FMT schema.
4+
Validates that the messages and params required by the Methodic Configurator configuration
5+
steps are present, also checks if a specific analysis can be performed and that logged records match their FMT schema.
66
77
SPDX-FileCopyrightText: 2024-2026 Amilcar do Carmo Lucas <amilcar.lucas@iav.de>
88
@@ -16,26 +16,28 @@
1616
from os import path as os_path
1717
from typing import Any
1818

19-
from ardupilot_methodic_configurator.log_analysis.backend_log_extraction import LogData, MessageSchema
19+
from backend_log_extraction import LogData, MessageSchema
2020

2121

22-
def load_analysis_plugins() -> dict[str, Any]:
23-
"""Load the analysis plugin from JSON."""
24-
plugin_file = os_path.join(
25-
os_path.dirname(os_path.abspath(__file__)),
26-
"analysis_plugins.json",
22+
def load_configuration_steps() -> dict[str, Any]:
23+
"""Load the Methodic Configurator configuration steps."""
24+
config_file = os_path.join(
25+
os_path.dirname(os_path.dirname(os_path.abspath(__file__))),
26+
"configuration_steps_ArduCopter.json",
2727
)
28+
2829
try:
29-
with open(plugin_file, encoding="utf-8") as file:
30+
with open(config_file, encoding="utf-8") as file:
3031
return json_load(file)
3132
except FileNotFoundError:
32-
logging_error("Analysis plugins '%s' not found", plugin_file)
33+
logging_error("Configuration file '%s' not found", config_file)
3334
except JSONDecodeError as e:
34-
logging_error("Error in analysis plugins '%s': %s", plugin_file, e)
35+
logging_error("Error in configuration file '%s': %s", config_file, e)
36+
3537
return {}
3638

3739

38-
ANALYSIS_PLUGINS = load_analysis_plugins()
40+
CONFIGURATION_STEPS = load_configuration_steps()
3941

4042

4143
@dataclass
@@ -47,17 +49,17 @@ class MessageValidation:
4749

4850

4951
@dataclass
50-
class PluginValidationResult:
51-
"""Validation result for one analysis plugin (analysis_plugins.json)."""
52+
class StepValidationResult:
53+
"""Validation result for configuration step."""
5254

53-
plugin: str
55+
step: str
5456
name: str
5557
valid: bool
5658
message_results: dict[str, MessageValidation]
5759

5860

5961
class LogQualityChecker:
60-
"""Checks whether a log is suitable for each analysis plugin."""
62+
"""Checks whether a log contains the required messages for each configuration step."""
6163

6264
def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> MessageValidation:
6365
"""
@@ -71,7 +73,6 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
7173
MessageValidation
7274
7375
"""
74-
# Store the issues iteratively
7576
issues: list[str] = []
7677

7778
if not schema.fields:
@@ -87,7 +88,6 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
8788

8889
if not records:
8990
issues.append(f"{schema.name} has no logging data")
90-
9191
else:
9292
record = records[0]
9393
actual_fields = [field for field in record.keys() if field != "mavpackettype"] # noqa: SIM118
@@ -100,32 +100,42 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
100100
issues=issues,
101101
)
102102

103-
def validate_fmt_plugins(self, log_data: LogData) -> list[PluginValidationResult]:
103+
def validate_configuration_steps(self, log_data: LogData) -> list[StepValidationResult]:
104104
"""
105-
Validate every analysis plugin.
105+
Validate the messages required by each configuration step.
106106
107107
Args:
108108
log_data: Parsed log.
109109
110110
Returns:
111-
List of plugin validation results.
111+
List of validation results.
112112
113113
"""
114-
results: list[PluginValidationResult] = []
114+
results: list[StepValidationResult] = []
115+
116+
for step_name, step in CONFIGURATION_STEPS["steps"].items():
117+
related_messages = step.get("related_bin_messages")
118+
if not related_messages:
119+
continue
115120

116-
for plugin_name, plugin in ANALYSIS_PLUGINS.items():
117-
plugin_valid = True
121+
step_valid = True
118122
message_results: dict[str, MessageValidation] = {}
119123

120-
for message_name in plugin["required_messages"]:
124+
for message_name, message_info in related_messages.items():
125+
required = message_info.get("required", False)
126+
121127
schema = log_data.schemas.get(message_name)
122128

123129
if schema is None:
124-
plugin_valid = False
125-
message_results[message_name] = MessageValidation(
130+
validation = MessageValidation(
126131
valid=False,
127132
issues=["Schema not found"],
128133
)
134+
135+
if required:
136+
step_valid = False
137+
138+
message_results[message_name] = validation
129139
continue
130140

131141
records = log_data.raw_messages.get(message_name, [])
@@ -135,16 +145,16 @@ def validate_fmt_plugins(self, log_data: LogData) -> list[PluginValidationResult
135145
records=records,
136146
)
137147

138-
if not validation.valid:
139-
plugin_valid = False
148+
if required and not validation.valid:
149+
step_valid = False
140150

141151
message_results[message_name] = validation
142152

143153
results.append(
144-
PluginValidationResult(
145-
plugin=plugin_name,
146-
name=plugin["name"],
147-
valid=plugin_valid,
154+
StepValidationResult(
155+
step=step_name,
156+
name=step.get("blog_text", step_name),
157+
valid=step_valid,
148158
message_results=message_results,
149159
)
150160
)

0 commit comments

Comments
 (0)