5.4 KiB
Architecture
Kaptan separates immutable board configuration from platform-owned runtime resources and portable flight logic.
board declaration
│
▼
F722 platform / RTIC application ──► data channel ──► MAVLink telemetry
│
├── physical sensor drivers
└── startup motor-pin inhibition
portable libraries
math ─► navigation ─► control ─► safety
Each F722 board contract pairs a board-owned UserConfig schema and explicit
FACTORY_USER_CONFIG with a board-owned ImmutableConfig. The immutable root
is one literal typestate manifest and the sole source of output inhibition,
physical routes, driver setup, sensor mount, bootstrap line rates, status LED,
image role, and service frequency. The user root contains only settings
consumed by that compiled driver graph.
The data channel owns rate selection, mailbox consumption, message encoding, and bounded TX classification. Board code supplies physical routes, target schema, and factory values; it does not receive generic output authority.
Configuration and runtime observability are separate, one-way planes:
Kaptan GCS custom MAVLink V2 messages
│ (future: verified signing, source binding, replay state)
▼
kaptan-config-mavlink ──► state-only ConfigProtocol
│ borrows
kaptan-flight-runtime
├── one ConfigManager ──► kaptan-config ──► flight schema/store
└── one bounded MAVLink log-sink queue
│
kaptan-diagnostics-mavlink payload adapter
│
platform-owned sole encoder / DMA TX link
The generated dialect is intentionally custom rather than a PARAM_* or QGC
adapter. The core uses numeric field IDs and typed scalar values; descriptor
text is metadata, not a wire identity. Discovery/value reads, exact-index
descriptor and enum-option requests, and structured results are custom-dialect
records. Runtime logs use one bounded text message with a conventional level
and flags. Remote writes use only schema-described typed scalar setters. The core
owns one RAM transaction and the distinction
between boot-active, committed, and editable candidate snapshots. In the
current P1 policy a commit is restart-only. It cannot mutate controller or
estimator state in flight.
Target-owned stores may serialize one bounded complete CBOR snapshot. SITL supplies the host file adapter and atomically replaces that snapshot through a same-directory temporary file. The serialization is not configuration state and is never exposed by the MAVLink protocol. Motor allocation/mixer topology is immutable compiled vehicle capability data, never a scalar field or CBOR candidate member. F722 now recovers operational settings from a generic two-slot journal before constructing consumers. Its directly wired local UART accepts only exact-target, CRC-valid configuration commands while physical outputs remain inhibited. CRC is integrity-only; a shared or remote GCS still needs production authentication, durable audit logging, source binding, and persistent anti-replay state. Disarmed activation and flight-consumer reconstruction remain separate reviewed work and cannot be implied by a valid snapshot or CRC.
Configuration wire layout 2.0 uses one exact response per descriptor or enum
option request. The first accepted transaction binds one source principal
through a bounded post-terminal replay lease; foreign traffic cannot evict a
lost result before that lease expires.
The MAVLink dialect root includes kaptan/config.xml, kaptan/log.xml, and
kaptan/error.xml.
The build watches every fragment and generates one message::kaptan module;
fragments are never separately generated Rust modules. kaptan-log itself has
no MAVLink, platform, time, allocation, or filesystem dependency; its sole
configuration coupling is compile-time enum metadata for LevelFilter.
kaptan-err-propagate independently owns explicitly assigned typed-error identity,
function-boundary propagation, and a bounded nonblocking ingress; it has
no logging, MAVLink, platform, filesystem, or clock dependency. Event creation
is independent from sink filtering, allowing a future blackbox and MAVLink to
select different policies. The platform drains typed errors before its bounded
critical and best-effort log queues and removes a pending record only after TX
admission. KAPTAN_LOG carries one conventional level plus one bounded text
field; KAPTAN_ERROR carries an explicitly assigned 16-bit ID and the bounded
file:line of the reporting boundary. Its
message kind already identifies a typed firmware error. Heartbeat and safety
telemetry remain separate from diagnostics.
See Configuration for the deployment matrix and GCS transaction contract, Logs for the receiver contract, and Errors for derived-error and failure-reporting scope.
Ownership rules
- A peripheral owner is local to the platform runtime.
- Portable crates use typed units and validated values rather than raw wire or timer representations.
- A safety permit is epoch-bound and must be revalidated at the only nonzero output boundary.
- A failed observation or numerical check does not partially commit estimator, controller, allocator, or safety state.