4.9 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 planes:
FILE_CONTROL / FILE_DATA
│
▼
kaptan-file-mavlink ──► virtual FileProvider
│
KCFG importer/exporter
│
ConfigManager ──► private store
kaptan-log / kaptan-err-reportable
│
▼
kaptan-diagnostics-mavlink ──► platform-owned encoder / DMA TX
The file dialect is intentionally Kaptan-native rather than standard MAVLink
FTP, PARAM_*, or a QGC adapter. Its two messages know only bounded paths,
bytes, positions, checksums, transfer ownership, and retries. The configuration
provider maps /config/user.kcfg to a canonical self-describing artifact.
KCFG carries generated metadata and a complete committed value set; the target
streams it without retaining a whole-file buffer. Saving imports and validates
one complete replacement candidate. The core distinguishes only immutable
boot-active values from the latest committed values. A save cannot mutate
controller or estimator state in flight.
Target-owned stores use private persistence formats. SITL atomically replaces a
bounded CBOR snapshot. F722 alternates compact KCSP snapshots between two
erase sectors, retaining only the old and replacement records across the commit
boundary. Neither format is exposed as the public KCFG file.
Motor allocation/mixer topology is immutable compiled vehicle capability data,
never a scalar field or persistence member. F722 recovers operational settings
before constructing consumers. Its directly wired local UART accepts only
exact-target, CRC-valid Kaptan file requests while physical outputs remain
inhibited. CRC is integrity-only; a shared or remote GCS still needs production
authentication, source binding, and persistent anti-replay state. Disarmed
activation and flight-consumer reconstruction remain separate reviewed work.
The MAVLink dialect root directly includes one-message XML leaves under
publish/ and transfer/. The exchange/ contract remains empty until a
current consumer justifies a message. There are no category index XML files or
separate enum catalogs. The build watches the definitions tree and generates
one generated::kaptan module; leaves 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-reportable independently owns explicitly assigned reportable-error
identity 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 reportable errors before its bounded critical and
best-effort log queues and removes a pending record only after TX admission.
LOG carries one conventional level plus one bounded text field; ERROR
carries an explicitly assigned 16-bit ID and the bounded file:line of the
reporting point. Its message kind already identifies a reportable firmware
error. Kaptan-native heartbeat and sensor publications remain separate from
diagnostics.
See Configuration for KCFG and the file-transfer 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.