feat(firmware): validate configuration and migrate sensor-driven flight APIs
Validate configuration through its owning schemas and keep board declarations separate from shared F722 resource ownership. Bound USB transitions, isolate transport failures and retain restart-only activation. Migrate navigation and flight consumers with the sensor and schema contracts. Require explicit installation data and synchronous output authority; board motor outputs remain inhibited. Validation: assembled-prefix host tests, strict Clippy, platform/USB tests and both ARM release builds. Final-source coverage and scoped Miri/Kani evidence are retained separately from hardware qualification.
This commit is contained in:
1 parent
fb1b8af2d1
commit
f9a61a086f
211 files changed
+45657
-12740
No files matched your search
@@ -290,3 +290,91 @@ fn recursive_tree_rejects_duplicate_display_keys() {
|
||||
Err(issue) if issue.rule() == ValidationRule::Inconsistent
|
||||
));
|
||||
}
|
||||
|
||||
#[derive(Config)]
|
||||
struct FloatRules {
|
||||
#[config(id = 1, key = "finite", unit = "", finite)]
|
||||
finite: f32,
|
||||
#[config(id = 2, key = "nonzero", unit = "", nonzero)]
|
||||
nonzero: f64,
|
||||
#[config(id = 3, key = "lower", unit = "", range(min = 0.0))]
|
||||
lower: f32,
|
||||
#[config(id = 4, key = "upper", unit = "", range(max = 1.0))]
|
||||
upper: f64,
|
||||
#[config(id = 5, key = "free", unit = "")]
|
||||
free: f64,
|
||||
#[config(id = 6, key = "nonzero32", unit = "", nonzero)]
|
||||
nonzero32: f32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scalar_rules_preserve_local_repair_and_float_domains() {
|
||||
let mut values = FloatRules {
|
||||
finite: f32::NAN,
|
||||
nonzero: 0.0,
|
||||
lower: f32::NAN,
|
||||
upper: f64::NAN,
|
||||
free: f64::NAN,
|
||||
nonzero32: 0.0,
|
||||
};
|
||||
// Every other field is invalid. A local repair must still succeed.
|
||||
values
|
||||
.set_field(FieldId::new(1), ConfigValue::F32(1.0))
|
||||
.unwrap();
|
||||
for (id, value, rule) in [
|
||||
(
|
||||
1,
|
||||
ConfigValue::F32(f32::INFINITY),
|
||||
ValidationRule::NonFinite,
|
||||
),
|
||||
(2, ConfigValue::F64(0.0), ValidationRule::Zero),
|
||||
(2, ConfigValue::F64(-0.0), ValidationRule::Zero),
|
||||
(3, ConfigValue::F32(f32::NAN), ValidationRule::Unordered),
|
||||
(4, ConfigValue::F64(f64::NAN), ValidationRule::Unordered),
|
||||
(6, ConfigValue::F32(0.0), ValidationRule::Zero),
|
||||
(6, ConfigValue::F32(-0.0), ValidationRule::Zero),
|
||||
] {
|
||||
let id = FieldId::new(id);
|
||||
let before = values.field_value(id);
|
||||
assert_eq!(
|
||||
values.set_field(id, value),
|
||||
Err(FieldWriteError::Violation(ConfigViolation::field(id, rule)))
|
||||
);
|
||||
assert_eq!(values.field_value(id), before);
|
||||
}
|
||||
// Neither nonzero nor a one-sided range implies finite.
|
||||
for (id, value) in [
|
||||
(2, ConfigValue::F64(f64::from_bits(0xfff0_0000_0000_0042))),
|
||||
(3, ConfigValue::F32(f32::INFINITY)),
|
||||
(4, ConfigValue::F64(f64::NEG_INFINITY)),
|
||||
(5, ConfigValue::F64(f64::from_bits(0x7ff8_0000_0000_1234))),
|
||||
(6, ConfigValue::F32(f32::INFINITY)),
|
||||
] {
|
||||
values.set_field(FieldId::new(id), value).unwrap();
|
||||
assert_eq!(values.field_value(FieldId::new(id)), Some(value));
|
||||
}
|
||||
values.validate().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rule_metadata_changes_fingerprints() {
|
||||
let descriptor = FloatRules::DESCRIPTORS[0];
|
||||
assert!(descriptor.finite);
|
||||
assert!(!descriptor.nonzero);
|
||||
assert!(FloatRules::DESCRIPTORS[1].nonzero);
|
||||
let original = kaptan_config::validation::__schema_id(&[descriptor]);
|
||||
assert_ne!(
|
||||
original,
|
||||
kaptan_config::validation::__schema_id(&[kaptan_config::FieldDescriptor {
|
||||
finite: false,
|
||||
..descriptor
|
||||
}])
|
||||
);
|
||||
assert_ne!(
|
||||
original,
|
||||
kaptan_config::validation::__schema_id(&[kaptan_config::FieldDescriptor {
|
||||
nonzero: true,
|
||||
..descriptor
|
||||
}])
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user