refactor(firmware): simplify configuration and diagnostics

This commit is contained in:
Onur Özkan committed 2026-08-23 00:40:36 +03:00
1 parent ba9c97ed3b
commit fdf82a5114
96 files changed
+1612 -2772

No files matched your search

@@ -2,8 +2,8 @@
use kaptan_config::{Config, ConfigManager, ConfigModel, ConfigStore, ConfigValue, FieldId};
use platform_stm32f7::{
F7ImmutableConfig, F722Hardware, F722ImmutableConfig, ImuMount, Mavlink, Mpu6000,
Mpu6000Config, Pa4, Pb0Pb1Pb4Pb5Low, Pd2ActiveLow, Severity, VerticalSensor,
F7ImmutableConfig, F722Hardware, F722ImmutableConfig, ImuMount, LevelFilter, Mavlink, Mpu6000,
Mpu6000Config, Pa4, Pb0Pb1Pb4Pb5Low, Pd2ActiveLow, VerticalSensor,
};
// Include the implementation as a child module so this platform-internal test
@@ -15,29 +15,17 @@ use target_config::UserConfigModel;
#[derive(Clone, kaptan_config::Config)]
struct MavlinkConfig {
#[config(
id = 101,
key = "mavlink.system_id",
unit = "id",
range(min = 1, max = 255)
)]
#[config(id = 101, key = "mavlink.system_id", unit = "id", range(min = 1))]
system_id: u8,
#[config(
id = 102,
key = "mavlink.component_id",
unit = "id",
range(min = 1, max = 255)
)]
#[config(id = 102, key = "mavlink.component_id", unit = "id", range(min = 1))]
component_id: u8,
#[config(id = 108, key = "mavlink.logging.enabled", unit = "bool")]
logging_enabled: bool,
#[config(
enum,
id = 105,
key = "mavlink.logging.maximum_severity",
unit = "mav_severity"
key = "mavlink.logging.level_filter",
unit = "log_level"
)]
maximum_log_severity: Severity,
log_level_filter: LevelFilter,
}
#[derive(Clone, kaptan_config::Config)]
@@ -118,8 +106,7 @@ fn factory() -> TestUserConfig {
mavlink: MavlinkConfig {
system_id: 1,
component_id: 1,
logging_enabled: true,
maximum_log_severity: Severity::Info,
log_level_filter: LevelFilter::Info,
},
telemetry: TelemetryConfig {
raw_imu_hz: 20,
@@ -167,21 +154,17 @@ impl Config for MalformedProjection {
fn mavlink_logging_policy_is_projected_and_validated_independently() {
assert_eq!(
core::mem::size_of::<target_config::F722UserRuntime>(),
10,
9,
"runtime projection must retain narrow board-native scalar widths"
);
let mut candidate = UserConfigModel::<TestUserConfig, F722ImmutableConfig>::new(factory());
candidate
.set_field(FieldId::new(108), ConfigValue::Bool(false))
.unwrap();
candidate
.set_field(FieldId::new(105), ConfigValue::U32(0))
.unwrap();
let active = candidate.validate(&IMMUTABLE).unwrap();
let runtime = target_config::project_runtime(&active, &IMMUTABLE).unwrap();
assert!(!runtime.mavlink_logging_enabled);
assert_eq!(runtime.mavlink_maximum_log_severity, Severity::Emergency);
assert_eq!(runtime.mavlink_log_level_filter, LevelFilter::Off);
}
#[test]
@@ -267,10 +267,9 @@ fn configuration_schema_is_generated_without_board_forwarding_code() {
"MAVLINK_COMPONENT_ID",
"RAW_IMU_HZ",
"HEARTBEAT_HZ",
"MAVLINK_MAXIMUM_LOG_SEVERITY",
"MAVLINK_LOG_LEVEL_FILTER",
"RANGE_HZ",
"OPTICAL_FLOW_HZ",
"MAVLINK_LOGGING_ENABLED",
] {
assert!(
platform_config.contains(&format!("const {semantic_id}: FieldId")),
@@ -308,16 +307,11 @@ fn f722_link_budget_reserves_only_deterministic_telemetry() {
let board = platform_source("src/f722/board.rs");
assert!(board.contains("SCHEDULED_TELEMETRY_BYTES_PER_SECOND"));
assert!(board.contains("SERVICE_HZ * SCHEDULED_FRAME_MAXIMUM_BYTES"));
assert_eq!(
board
.matches("self.drain_one_mavlink_log_record();")
.count(),
1,
"each service turn must make exactly one bounded log admission attempt"
);
assert!(board.contains("if runtime.mavlink_logging_enabled"));
assert!(board.contains("LogFilter::up_to(runtime.mavlink_maximum_log_severity)"));
assert!(board.contains("LogFilter::disabled()"));
assert!(board.contains("self.drain_one_mavlink_diagnostic();"));
assert!(board.contains("let mavlink_log_filter = runtime.mavlink_log_level_filter;"));
assert!(board.contains("LogSinkQueue::new(mavlink_log_filter)"));
assert!(!board.contains("mavlink_logging_enabled"));
assert!(!board.contains("LogFilter"));
for periodic_diagnostic_policy in [
"ERROR_RECORDS_PER_SECOND",
"LOG_RECORDS_PER_SECOND",
@@ -341,6 +335,11 @@ fn mavlink_transport_faults_do_not_recurse_or_retain_dead_accounting() {
let transport = platform_source("src/f722/data_channel.rs");
let portable_channel = platform_source("../../libs/kaptan-data-channel/src/lib.rs");
assert!(
!board.contains("mavlink transmit dma fault"),
"the MAVLink sink must not report its own transmit failure through itself"
);
for recursive_path in [
"drain_transport_faults",
"take_transport_fault",
@@ -368,3 +367,30 @@ fn mavlink_transport_faults_do_not_recurse_or_retain_dead_accounting() {
);
}
}
#[test]
fn f722_producers_keep_logs_and_typed_errors_separate() {
let board = platform_source("src/f722/board.rs");
let logger = platform_source("../../libs/kaptan-log/src/facade.rs");
let errors = platform_source("../../libs/kaptan-err-propagate/src/ingress.rs");
for macro_name in [
"kaptan_log::debug!",
"kaptan_log::info!",
"kaptan_log::warn!",
"kaptan_log::error!",
] {
assert!(
board.contains(macro_name),
"f722 does not exercise {macro_name}"
);
}
assert!(board.contains("#[kaptan_err_propagate::propagate]"));
assert!(!board.contains("report_error"));
assert!(!board.contains("report_static_error"));
assert!(logger.contains("GLOBAL_INGRESS_CAPACITY"));
assert!(logger.contains("compare_exchange"));
assert!(errors.contains("AtomicU8"));
assert!(errors.contains("UnsafeCell<MaybeUninit<ErrorRecord>>"));
assert!(errors.contains("compare_exchange"));
}