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

+3 -3
View File
@@ -9,20 +9,20 @@ version.workspace = true
workspace = true
[dependencies]
kaptan-err-propagate = { path = "../../libs/kaptan-err-propagate" }
kaptan-control = { path = "../../libs/kaptan-control" }
kaptan-config = { path = "../../libs/kaptan-config" }
kaptan-config-mavlink = { path = "../../libs/kaptan-config-mavlink" }
kaptan-flight-config = { path = "../../libs/kaptan-flight-config" }
kaptan-flight-runtime = { path = "../../libs/kaptan-flight-runtime" }
kaptan-log = { path = "../../libs/kaptan-log", features = ["facade"] }
kaptan-log-mavlink = { path = "../../libs/kaptan-log-mavlink" }
kaptan-log = { path = "../../libs/kaptan-log" }
kaptan-diagnostics-mavlink = { path = "../../libs/kaptan-diagnostics-mavlink" }
kaptan-mavlink = { path = "../../libs/kaptan-mavlink" }
kaptan-math = { path = "../../libs/kaptan-math" }
kaptan-navigation = { path = "../../libs/kaptan-navigation", features = ["sitl"] }
kaptan-safety = { path = "../../libs/kaptan-safety" }
kaptan-time = { path = "../../libs/kaptan-time" }
minicbor = "0.25"
log = { version = "0.4.33", default-features = false }
[dev-dependencies]
mavlink = { version = "0.18", default-features = false, features = ["embedded"] }
+5 -29
View File
@@ -1,32 +1,8 @@
//! Host-only standard-log facade composition.
//! Host-side access to the common bounded log ingress.
use std::sync::Once;
use kaptan_log::LogRecord;
use kaptan_log::{FacadeIngress, GlobalLogger, LogRecord};
const SITL_LOG_INGRESS_CAPACITY: usize = 16;
static SITL_LOG_INGRESS: FacadeIngress<SITL_LOG_INGRESS_CAPACITY> = FacadeIngress::new();
static SITL_LOGGER: GlobalLogger<SITL_LOG_INGRESS_CAPACITY> =
GlobalLogger::new(&SITL_LOG_INGRESS, sitl_forbidden_log_context);
static INSTALL_SITL_LOGGER: Once = Once::new();
const fn sitl_forbidden_log_context() -> bool {
false
}
/// Installs the host-only standard logging facade once for the SITL process.
///
/// SITL has no ISR, panic, or hard-fault context. Flight targets deliberately
/// do not enable this host-only feature.
pub fn install_log_facade() {
INSTALL_SITL_LOGGER.call_once(|| {
SITL_LOGGER
.install()
.expect("SITL owns the process-global log facade")
});
}
/// Removes one transport-neutral event for composition-level sink fanout.
pub(super) fn take() -> Option<LogRecord> {
SITL_LOG_INGRESS.take()
/// Visits one transport-neutral event for composition-level sink fanout.
pub(super) fn drain_one<R>(consume: impl FnOnce(&LogRecord) -> R) -> Option<R> {
kaptan_log::drain_one(consume)
}
-1
View File
@@ -11,7 +11,6 @@ mod store;
#[cfg(test)]
mod tests;
pub use logging::install_log_facade;
pub use runtime::{CAPABILITIES, SitlConfigRuntime, configuration_service};
pub use store::{
FileConfigStore, FileStoreError, default_profile, load_profile, write_default_profile,
+6 -7
View File
@@ -2,10 +2,11 @@
use kaptan_config::ConfigManager;
use kaptan_config_mavlink::{ConfigCommand, ConfigProtocol, Principal, ServiceResponse, Target};
use kaptan_diagnostics_mavlink::encode_log;
use kaptan_flight_config::{CandidateProfile, VehicleCapabilities, VehicleProfile};
use kaptan_flight_runtime::FlightRuntime;
use kaptan_log::TransportAdmission;
use kaptan_log_mavlink::{DiagnosticPayload, encode_diagnostic};
use kaptan_mavlink::message::kaptan::KAPTAN_LOG_DATA;
use super::{FileConfigStore, logging};
@@ -51,12 +52,11 @@ impl SitlConfigRuntime {
/// Drains one standard `log` facade record and exposes the generated
/// diagnostic payload for the host's sole MAVLink link owner. This
/// host-only harness accepts the bounded handoff synchronously.
pub fn pending_diagnostic_payload(&mut self) -> Option<DiagnosticPayload> {
if let Some(record) = logging::take() {
self.runtime.publish_log_event(record);
}
pub fn pending_log_payload(&mut self) -> Option<KAPTAN_LOG_DATA> {
let runtime = &mut self.runtime;
let _ = logging::drain_one(|record| runtime.publish_log_event(*record));
self.runtime
.submit_next_mavlink(|record| (TransportAdmission::Accepted, encode_diagnostic(record)))
.submit_next_mavlink(|record| (TransportAdmission::Accepted, encode_log(record)))
}
}
@@ -64,7 +64,6 @@ impl SitlConfigRuntime {
/// SITL/GCS integration. Flight targets must supply authenticated authority
/// and a reviewed journal/activation coordinator before constructing one.
pub fn configuration_service(store: FileConfigStore) -> Result<SitlConfigRuntime, String> {
logging::install_log_facade();
let runtime = FlightRuntime::recover(CandidateProfile::factory(), CAPABILITIES, store)
.map_err(|error| format!("configuration recovery failed: {error:?}"))?;
Ok(SitlConfigRuntime {
+5 -1
View File
@@ -7,11 +7,11 @@ use std::{
};
use kaptan_config::ConfigStore;
use kaptan_err_propagate::KaptanError;
use kaptan_flight_config::{
CandidateProfile, CborEncodeError, CborError, MAXIMUM_CANDIDATE_BYTES, VehicleProfile,
decode_candidate, encode_candidate,
};
use kaptan_log::KaptanError;
use super::{CAPABILITIES, configuration_service};
@@ -19,12 +19,16 @@ use super::{CAPABILITIES, configuration_service};
#[derive(Debug, KaptanError)]
pub enum FileStoreError {
/// Host filesystem operation failed.
#[kaptan_error(id = 12101)]
Io(std::io::Error),
/// The bounded file record did not decode and validate.
#[kaptan_error(id = 12102)]
Cbor(CborError),
/// The fixed snapshot buffer could not encode the complete candidate.
#[kaptan_error(id = 12103)]
Encode,
/// Factory-only startup deliberately has no durable configuration path.
#[kaptan_error(id = 12104)]
FactoryOnly,
}
+6 -8
View File
@@ -2,7 +2,6 @@ use std::fs;
use kaptan_config::{ConfigModel, ConfigStore};
use kaptan_flight_config::{CandidateProfile, decode_candidate};
use kaptan_log_mavlink::DiagnosticPayload;
use kaptan_mavlink::{
encoder::MavlinkEncoder,
message::{Message, kaptan::MavMessage},
@@ -49,15 +48,14 @@ fn standard_log_macro_reaches_the_generated_mavlink_log_payload() {
let _ = fs::remove_file(&path);
let mut service = configuration_service(FileConfigStore::new(&path)).unwrap();
log::info!("SITL configuration service ready");
let Some(DiagnosticPayload::Log(payload)) = service.pending_diagnostic_payload() else {
panic!("info facade record must reach KAPTAN_LOG");
};
assert_eq!(payload.level, kaptan_log::Severity::Info.wire_value());
kaptan_log::info!("SITL configuration service ready");
let payload = service
.pending_log_payload()
.expect("info facade record must reach KAPTAN_LOG");
assert_eq!(payload.level, 6);
let message = std::str::from_utf8(&payload.message[..usize::from(payload.message_length)])
.expect("facade text remains UTF-8");
assert!(message.contains("config::tests"));
assert!(message.ends_with("SITL configuration service ready"));
assert_eq!(message, "SITL configuration service ready");
let mut encoder = MavlinkEncoder::new(1, 1);
let frame = encoder.custom(&payload);
assert_eq!(frame.message_id(), 51_020);
+4 -1
View File
@@ -4,7 +4,7 @@
//! dialect. It is confined to one host network namespace and is versioned so
//! malformed simulator traffic never becomes estimator or motor authority.
use kaptan_log::KaptanError;
use kaptan_err_propagate::KaptanError;
use std::net::SocketAddr;
pub const SENSOR_PORT: u16 = 14_660;
@@ -42,8 +42,11 @@ pub const STATUS_OUTPUT_PERMITTED: u16 = 1 << 3;
pub const STATUS_ACTUATOR_TRANSPORT: u16 = 1 << 4;
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
pub enum PacketError {
#[kaptan_error(id = 12001)]
Length,
#[kaptan_error(id = 12002)]
Version,
#[kaptan_error(id = 12003)]
NonFinite,
}