refactor(firmware): simplify configuration and diagnostics
This commit is contained in:
1 parent
ba9c97ed3b
commit
fdf82a5114
96 files changed
+1612
-2772
No files matched your search
@@ -10,5 +10,6 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
kaptan-config = { path = "../kaptan-config" }
|
||||
kaptan-err-propagate = { path = "../kaptan-err-propagate" }
|
||||
kaptan-log = { path = "../kaptan-log" }
|
||||
minicbor = { version = "0.25", features = ["derive"] }
|
||||
@@ -3,7 +3,7 @@
|
||||
use kaptan_config::{
|
||||
ConfigModel, ConfigValue, ConfigViolation, FieldWriteError, ValidationRule, ValueKind,
|
||||
};
|
||||
use kaptan_log::KaptanError;
|
||||
use kaptan_err_propagate::KaptanError;
|
||||
use minicbor::{Decoder, Encoder, encode::Write};
|
||||
|
||||
use crate::{CandidateProfile, FORMAT_VERSION, SCHEMA_ID, VehicleCapabilities};
|
||||
@@ -17,12 +17,16 @@ const SCHEMA_KEY: u16 = u16::MAX;
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
|
||||
pub enum CborError {
|
||||
/// The supplied payload exceeded the bounded configuration storage budget.
|
||||
#[kaptan_error(id = 3001)]
|
||||
TooLarge,
|
||||
/// CBOR was malformed or did not match a supported versioned wire record.
|
||||
#[kaptan_error(id = 3002)]
|
||||
Malformed,
|
||||
/// A second CBOR item followed the candidate snapshot.
|
||||
#[kaptan_error(id = 3003)]
|
||||
TrailingData,
|
||||
/// The decoded candidate violated complete schema/capability validation.
|
||||
#[kaptan_error(id = 3004)]
|
||||
InvalidProfile(ConfigViolation),
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ pub struct VehicleProfile {
|
||||
pub(crate) thrust: ThrustSettings,
|
||||
pub(crate) rate_pid: PidSettings,
|
||||
pub(crate) actuator_limits: ActuatorLimits,
|
||||
pub(crate) mavlink_logging: super::MavlinkLoggingSettings,
|
||||
pub(crate) mavlink_logging: kaptan_log::LevelFilter,
|
||||
pub(crate) mixer: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ impl VehicleProfile {
|
||||
self.actuator_limits
|
||||
}
|
||||
/// Immutable boot-active policy for the MAVLink diagnostic sink.
|
||||
pub const fn mavlink_logging(self) -> super::MavlinkLoggingSettings {
|
||||
pub const fn mavlink_logging(self) -> kaptan_log::LevelFilter {
|
||||
self.mavlink_logging
|
||||
}
|
||||
pub const fn mixer(self) -> [[f32; 4]; 4] {
|
||||
|
||||
@@ -4,11 +4,11 @@ use kaptan_config::{
|
||||
Config, ConfigModel, ConfigValue, ConfigViolation, FieldDescriptor, FieldId, FieldWriteError,
|
||||
ValidationRule,
|
||||
};
|
||||
use kaptan_log::Severity;
|
||||
use kaptan_log::LevelFilter;
|
||||
|
||||
use super::{
|
||||
ActuatorLimits, AidingSettings, ControlSettings, MavlinkLoggingSettings, PidSettings,
|
||||
SafetySettings, ThrustSettings, TimingSettings, VehicleCapabilities, VehicleProfile,
|
||||
ActuatorLimits, AidingSettings, ControlSettings, PidSettings, SafetySettings, ThrustSettings,
|
||||
TimingSettings, VehicleCapabilities, VehicleProfile,
|
||||
control::{
|
||||
ActuatorLimitsCandidate, AidingCandidate, ControlCandidate, PidCandidate, ThrustCandidate,
|
||||
},
|
||||
@@ -18,7 +18,7 @@ use super::{
|
||||
};
|
||||
|
||||
/// Current persisted CBOR schema for the vehicle candidate.
|
||||
pub const FORMAT_VERSION: u16 = 2;
|
||||
pub const FORMAT_VERSION: u16 = 3;
|
||||
|
||||
/// Complete editable vehicle candidate.
|
||||
///
|
||||
@@ -83,8 +83,7 @@ impl CandidateProfile {
|
||||
slew_per_second: 8.0,
|
||||
},
|
||||
mavlink_logging: MavlinkLoggingCandidate {
|
||||
enabled: true,
|
||||
maximum_severity: Severity::Info,
|
||||
level_filter: LevelFilter::Info,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -147,8 +146,7 @@ impl CandidateProfile {
|
||||
slew_per_second: actuator_limits.slew_per_second(),
|
||||
},
|
||||
mavlink_logging: MavlinkLoggingCandidate {
|
||||
enabled: mavlink_logging.enabled(),
|
||||
maximum_severity: mavlink_logging.maximum_severity(),
|
||||
level_filter: mavlink_logging,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -203,10 +201,7 @@ impl CandidateProfile {
|
||||
maximum: self.actuator_limits.maximum,
|
||||
slew_per_second: self.actuator_limits.slew_per_second,
|
||||
},
|
||||
mavlink_logging: MavlinkLoggingSettings::new(
|
||||
self.mavlink_logging.enabled,
|
||||
self.mavlink_logging.maximum_severity,
|
||||
),
|
||||
mavlink_logging: self.mavlink_logging.level_filter,
|
||||
mixer: capabilities.mixer(),
|
||||
})
|
||||
}
|
||||
@@ -258,7 +253,7 @@ impl ConfigModel for CandidateProfile {
|
||||
mod tests {
|
||||
use kaptan_config::{ConfigModel, ConfigValue, FieldId, FieldWriteError, ValidationRule};
|
||||
|
||||
use super::{CandidateProfile, Severity, VehicleCapabilities};
|
||||
use super::{CandidateProfile, LevelFilter, VehicleCapabilities};
|
||||
use crate::profile::ids;
|
||||
|
||||
const CAPABILITIES: VehicleCapabilities = VehicleCapabilities::quad_x();
|
||||
@@ -268,8 +263,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
crate::SCHEMA_ID,
|
||||
[
|
||||
0xc4, 0xf6, 0x36, 0xc0, 0x29, 0xd2, 0x3e, 0x29, 0xa3, 0x85, 0x5b, 0x36, 0xb7, 0xb3,
|
||||
0x59, 0x9c,
|
||||
0xa1, 0x4c, 0x28, 0xba, 0x08, 0xc0, 0xfd, 0xc3, 0xe2, 0x54, 0x7d, 0x77, 0x40, 0x3c,
|
||||
0xed, 0x94,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -350,39 +345,35 @@ mod tests {
|
||||
#[test]
|
||||
fn mavlink_logging_policy_is_persisted_and_restart_only() {
|
||||
let mut candidate = CandidateProfile::factory();
|
||||
let severity_descriptor = CandidateProfile::descriptors()
|
||||
.find(|descriptor| descriptor.display_key == "mavlink.logging.maximum_severity")
|
||||
let level_descriptor = CandidateProfile::descriptors()
|
||||
.find(|descriptor| descriptor.display_key == "mavlink.logging.level_filter")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
severity_descriptor.enum_options,
|
||||
Severity::CONFIG_ENUM_OPTIONS
|
||||
level_descriptor.enum_options,
|
||||
LevelFilter::CONFIG_ENUM_OPTIONS
|
||||
);
|
||||
candidate
|
||||
.set_field(
|
||||
descriptor_id("mavlink.logging.enabled"),
|
||||
ConfigValue::Bool(false),
|
||||
descriptor_id("mavlink.logging.level_filter"),
|
||||
ConfigValue::U32(LevelFilter::Off.wire_value().into()),
|
||||
)
|
||||
.unwrap();
|
||||
let active = candidate.validate(&CAPABILITIES).unwrap();
|
||||
assert!(!active.mavlink_logging().enabled());
|
||||
assert_eq!(active.mavlink_logging(), LevelFilter::Off);
|
||||
candidate
|
||||
.set_field(
|
||||
descriptor_id("mavlink.logging.maximum_severity"),
|
||||
ConfigValue::U32(5),
|
||||
descriptor_id("mavlink.logging.level_filter"),
|
||||
ConfigValue::U32(LevelFilter::Trace.wire_value().into()),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
candidate
|
||||
.validate(&CAPABILITIES)
|
||||
.unwrap()
|
||||
.mavlink_logging()
|
||||
.maximum_severity(),
|
||||
Severity::Notice
|
||||
candidate.validate(&CAPABILITIES).unwrap().mavlink_logging(),
|
||||
LevelFilter::Trace
|
||||
);
|
||||
assert!(matches!(
|
||||
candidate.set_field(
|
||||
descriptor_id("mavlink.logging.maximum_severity"),
|
||||
ConfigValue::U32(8),
|
||||
descriptor_id("mavlink.logging.level_filter"),
|
||||
ConfigValue::U32(6),
|
||||
),
|
||||
Err(FieldWriteError::Violation(issue))
|
||||
if issue.rule() == ValidationRule::InvalidEnumValue
|
||||
@@ -390,22 +381,21 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_persisted_log_severity_is_retained_exactly() {
|
||||
for raw in 0..=7 {
|
||||
fn every_persisted_log_filter_is_retained_exactly() {
|
||||
for raw in 0..=5 {
|
||||
let mut candidate = CandidateProfile::factory();
|
||||
candidate
|
||||
.set_field(
|
||||
descriptor_id("mavlink.logging.maximum_severity"),
|
||||
descriptor_id("mavlink.logging.level_filter"),
|
||||
ConfigValue::U32(raw),
|
||||
)
|
||||
.expect("descriptor range accepts the stable severity");
|
||||
.expect("descriptor accepts the stable level filter");
|
||||
assert_eq!(
|
||||
candidate
|
||||
.validate(&CAPABILITIES)
|
||||
.expect("valid complete profile")
|
||||
.mavlink_logging()
|
||||
.maximum_severity(),
|
||||
Severity::try_from_wire(u8::try_from(raw).unwrap()).unwrap()
|
||||
.mavlink_logging(),
|
||||
LevelFilter::try_from_wire(u8::try_from(raw).unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,16 @@
|
||||
//! Persisted, restart-only MAVLink diagnostic-sink policy.
|
||||
|
||||
use kaptan_config::Config;
|
||||
use kaptan_log::Severity;
|
||||
use kaptan_log::LevelFilter;
|
||||
|
||||
/// Candidate policy for the MAVLink diagnostic sink.
|
||||
#[derive(Clone, Copy, Config)]
|
||||
pub(super) struct MavlinkLoggingCandidate {
|
||||
#[config(id = 24, key = "mavlink.logging.enabled", unit = "bool")]
|
||||
pub(super) enabled: bool,
|
||||
#[config(
|
||||
enum,
|
||||
id = 25,
|
||||
key = "mavlink.logging.maximum_severity",
|
||||
unit = "mav_severity"
|
||||
key = "mavlink.logging.level_filter",
|
||||
unit = "log_level"
|
||||
)]
|
||||
pub(super) maximum_severity: Severity,
|
||||
}
|
||||
|
||||
/// Immutable boot-active policy for the MAVLink diagnostic sink.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct MavlinkLoggingSettings {
|
||||
enabled: bool,
|
||||
maximum_severity: Severity,
|
||||
}
|
||||
|
||||
impl MavlinkLoggingSettings {
|
||||
pub(crate) const fn new(enabled: bool, maximum_severity: Severity) -> Self {
|
||||
Self {
|
||||
enabled,
|
||||
maximum_severity,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the MAVLink diagnostic sink accepts records.
|
||||
pub const fn enabled(self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
/// Maximum accepted MAVLink severity, from Emergency (0) through Debug (7).
|
||||
pub const fn maximum_severity(self) -> Severity {
|
||||
self.maximum_severity
|
||||
}
|
||||
pub(super) level_filter: LevelFilter,
|
||||
}
|
||||
@@ -13,4 +13,3 @@ pub use active::{
|
||||
TimingSettings, VehicleCapabilities, VehicleProfile,
|
||||
};
|
||||
pub use candidate::{CandidateProfile, FORMAT_VERSION};
|
||||
pub use mavlink_logging::MavlinkLoggingSettings;
|
||||
Reference in new issue
Block a user