From 964645164552a4244e0108c6903d387387e11729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=96zkan?= Date: Sun, 9 Aug 2026 22:08:20 +0300 Subject: [PATCH] docs: document configuration and diagnostics contracts --- docs/src/SUMMARY.md | 3 + docs/src/architecture.md | 53 ++++++++++++++ docs/src/boards/geprc-f722-v2.md | 6 ++ docs/src/boards/kakute-f7-mini-v3.md | 6 ++ docs/src/configuration.md | 102 +++++++++++++++++++++++++++ docs/src/errors.md | 47 ++++++++++++ docs/src/index.md | 11 ++- docs/src/logs.md | 61 ++++++++++++++++ docs/src/mavlink.md | 9 +++ docs/src/reference.md | 35 +++++---- docs/src/sitl.md | 18 +++++ 11 files changed, 336 insertions(+), 15 deletions(-) create mode 100644 docs/src/configuration.md create mode 100644 docs/src/errors.md create mode 100644 docs/src/logs.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 3ea6bd8..9b7a1ca 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,6 +6,9 @@ - [Architecture](architecture.md) - [Safety boundary](safety-boundary.md) - [MAVLink and telemetry](mavlink.md) +- [Configuration](configuration.md) +- [Logs](logs.md) +- [Errors](errors.md) - [Boards](boards/index.md) - [Kakute F7 Mini V3](boards/kakute-f7-mini-v3.md) - [GEPRC GEP-F722-HD V2](boards/geprc-f722-v2.md) diff --git a/docs/src/architecture.md b/docs/src/architecture.md index 6834f30..ee90050 100644 --- a/docs/src/architecture.md +++ b/docs/src/architecture.md @@ -24,6 +24,59 @@ The data channel owns rate selection, mailbox consumption, message encoding, and bounded TX classification. Board code supplies physical routes and telemetry configuration; it does not receive generic output authority. +Configuration and runtime observability are separate, one-way planes: + +```text +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/CBOR + └── one kaptan-log hub + │ + kaptan-log-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, bounded +descriptor pages, and structured results are custom-dialect records. Runtime +logs use one bounded text message with MAVLink severity and flags. CBOR import uses a fixed +4 KiB transaction buffer and +fixed 192-byte chunks; its decoded candidate still goes through the same whole +profile validation path. 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. + +One current CBOR profile format is a bounded complete snapshot. There is no +migration reader: any other format is rejected. SITL supplies the host file +adapter and persists a nonzero generation alongside its raw profile payload. +Motor allocation/mixer topology is immutable compiled +vehicle capability data, never a scalar field or CBOR candidate member. The +bare-metal receiver continues to reject inbound control authority. Target +persistence, authenticated ingress, durable audit logging, disarmed +activation, and atomic consumer reconstruction remain separate reviewed work +and cannot be implied by a valid CBOR file or CRC. + +The MAVLink dialect root includes `kaptan/config.xml` and `kaptan/log.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, filesystem, or configuration +dependency. It assigns bounded Critical and BestEffort queues for text logs. +The platform drains a record only after TX admission; the diagnostic wire +contract deliberately contains only severity, flags, bounded text length, and +text. Local saturation accounting remains inside the hub, facade, and producer +mailboxes; heartbeat and safety telemetry remain separate from diagnostic text. + +See [Configuration](configuration.md) for the deployment matrix and GCS upload +contract, [Logs](logs.md) for the receiver contract, and [Errors](errors.md) +for derived-error and failure-reporting scope. + ## Ownership rules - A peripheral owner is local to the platform runtime. diff --git a/docs/src/boards/geprc-f722-v2.md b/docs/src/boards/geprc-f722-v2.md index 8bd5d0e..3bcbd51 100644 --- a/docs/src/boards/geprc-f722-v2.md +++ b/docs/src/boards/geprc-f722-v2.md @@ -3,6 +3,12 @@ The GEPRC GEP-F722-HD V2 board declaration uses the ICM-42688-P on SPI3 and MAVLink telemetry on USART2. It declares no vertical sensor stream. +Its immutable board policy selects the ICM-42688-P yaw-180° mount, logical +MAVLink `Serial2`, endpoint `1/1`, 115200 baud, the documented telemetry +schedule, and an `INFO` optional-log threshold. The platform verifies these +values against the checked SPI3/USART2 typestate route before it enables +peripherals. They are compiled image policy, not ground-station parameters. + Build and package from the workspace root: ```sh diff --git a/docs/src/boards/kakute-f7-mini-v3.md b/docs/src/boards/kakute-f7-mini-v3.md index 1e56618..df6a063 100644 --- a/docs/src/boards/kakute-f7-mini-v3.md +++ b/docs/src/boards/kakute-f7-mini-v3.md @@ -5,6 +5,12 @@ MAVLink telemetry on USART1, and the MTF01 range/optical-flow route on UART4. The checked-in manufacturer datasheet is `boards/kakute-f7-mini-v3/datasheet.pdf`. +Its immutable board policy selects the MPU-6000 body-aligned mount, logical +MAVLink `Serial1`, endpoint `1/1`, 115200 baud, the documented telemetry +schedule, and an `INFO` optional-log threshold. The platform verifies these +values against the checked SPI1/USART1/MTF01 typestate route before it enables +peripherals. They are compiled image policy, not ground-station parameters. + ## Build and package From the workspace root: diff --git a/docs/src/configuration.md b/docs/src/configuration.md new file mode 100644 index 0000000..a8d7ff1 --- /dev/null +++ b/docs/src/configuration.md @@ -0,0 +1,102 @@ +# Configuration + +Kaptan has one generic configuration lifecycle crate, `kaptan-config`. It +owns descriptors, typed writes, transactions, validation, generations, and +stores. It does not grow a crate per subsystem. Flight-specific values live in +the single `kaptan-flight-config` candidate; board electrical topology remains +in the immutable board declaration. + +## Current deployment matrix + +| Deployment | Configuration consumed today | Remote writes | +| --- | --- | --- | +| `kaptan-sitl serve --config FILE.cbor` | One validated Quad-X profile at process construction. | No live MAVLink endpoint is attached yet. | +| `kaptan-sitl serve` | The validated factory Quad-X profile. | No persistent store; commits are rejected. | +| STM32F722 telemetry image | Immutable compiled `BoardConfig` plus checked typestate routes. | Disabled: all inbound MAVLink remains discarded. | + +The current SITL profile has only settings consumed by its estimator, +controller, safety supervisor, allocator envelope, or log hub: + +- prearm dwell; +- IMU, local-aiding, and command freshness/timing; +- position/velocity aiding variance; +- outer-loop gains and acceleration limits; +- mass, collective-thrust, and tilt limits; +- rate PID gains and limits; +- actuator minimum, maximum, and slew limits; and +- the restart-only maximum optional log severity. + +The fixed Quad-X mixer is intentionally not configurable. It is reviewed +capability data, not an operator-editable array. + +Each editable field declares its ID, display key, unit, default, scalar type, +and local validation in one `#[config(...)]` attribute. The derive generates +the descriptor registry and local validation from that declaration; the only +handwritten checks are whole-profile physical relationships such as thrust +margin, timing ordering, and actuator limits. + +## Immutable F722 board policy + +The checked-in F722 boards consume these compiled `BoardConfig` settings before +peripheral initialization: + +- IMU model and its fixed body mount (`BodyAligned` or `Yaw180`); +- logical MAVLink port, endpoint IDs, and baud rate; +- vertical-sensor capability and telemetry schedule; and +- maximum optional MAVLink log severity. + +The platform compares that metadata with the selected `F722BoardRoutes` before +claiming pins, UARTs, DMA, or IRQs. A board declaration therefore cannot claim +an MPU-6000 while selecting the ICM route, select the wrong serial port or +mount, or request a baud rate that cannot carry the fixed link budget. The +physical port, sensor driver, pins, DMA, timers, and calibration are not file +configuration and are not GCS-editable. + +F722’s log threshold is immutable board policy. It is deliberately separate +from the SITL profile’s `observability.maximum_log_level`: the F722 image does +not construct a runtime `ConfigManager` or profile store. + +## One CBOR profile format + +There is one unreleased raw profile blob format: + +- it is a CBOR map keyed by the discovered numeric `FieldId`s; +- key `0` is `profile_format = 1` and reserved key `65535` is the 16-byte + `schema_id = "KAPTANPROFILE-01"`; +- the complete blob is at most 4 KiB; and +- malformed, trailing, wrong-format, non-finite, out-of-range, cross-field, + and capability-invalid values are rejected. + +The map is exact: it has those 26 keys once each. Unknown, duplicate, missing, +or indefinite-map keys are rejected. That keeps the unreleased file contract +unambiguous instead of silently accepting undeclared extensions. + +There is no migration path because no version has shipped. The raw blob is the +future GCS import/export representation. The SITL file is a +private host envelope `[generation, raw-profile-blob]`; it is not an upload +blob and must not be sent to `IMPORT_*` directly. + +## Future GCS upload contract + +The custom dialect is prepared for a first-party GCS without borrowing +`PARAM_*` semantics. A client will: + +1. send `KAPTAN_CONFIG_INFO_REQUEST` and require the exact protocol, profile + format, and schema ID in the correlated `KAPTAN_CONFIG_INFO` reply; +2. request descriptors and values as needed; +3. open a transaction with `KAPTAN_CONFIG_BEGIN`; +4. either issue typed setters or begin a raw-CBOR upload with the advertised + schema ID, then send aligned idempotent chunks in any order; +5. validate and commit; and +6. treat `COMMITTED_RESTART_REQUIRED` as persistence only, never live + activation. + +An accepted import begin returns a server-issued transfer ID. Every chunk and +finish request echoes it, preventing delayed data from an earlier transfer +from entering the current one. The service validates CRC-32C and the entire +candidate before it replaces the RAM transaction. + +This is protocol groundwork, not a claim of active aircraft configuration: +F722 needs authenticated ingress, source binding and replay protection, +journalled target storage, a disarmed/inhibited activation permit, and atomic +consumer rebuild/reset before it may accept any configuration command. diff --git a/docs/src/errors.md b/docs/src/errors.md new file mode 100644 index 0000000..05376f8 --- /dev/null +++ b/docs/src/errors.md @@ -0,0 +1,47 @@ +# Errors + +Public Kaptan error enums derive the pure `KaptanError` implementation: + +```rust +#[derive(Debug, kaptan_log::KaptanError)] +enum SensorError { + TransferFault, + UnexpectedIdentity(u8), +} +``` + +The derive implements `core::error::Error`, `Display`, and `ErrorReport`. It +creates a bounded human-facing `module::Type::Variant` message without +allocating, publishing telemetry, exposing generic source values, or changing +safety state. Renaming a module, type, or variant changes that text; it is not +a stable machine protocol identity. + +Normal-task code may use `log::error!("{error}")`; it is routed as a bounded +`KAPTAN_ERROR`. ISR-adjacent flight paths may enqueue the derived static +message through their existing bounded mailbox. Neither route is a replacement +for safety state, actuator inhibit, or typed configuration results. + +## What the receiver sees + +- Configuration writes receive authoritative structured failures through + `KAPTAN_CONFIG_RESULT`: operation, lifecycle state, field IDs, validation + rule, and protocol error code. +- Runtime driver and link faults reach the F722 MAVLink worker as + `KAPTAN_ERROR` text, subject to bounded transport admission. The message + carries no per-error numeric catalog: a `KaptanError` derive supplies its + type/variant display identity. +- A rejected configuration operation may enqueue a companion `KAPTAN_ERROR` + containing the high-level `ProtocolError` identity. It is intentionally not + correlated and carries no field/rule detail; the matching + `KAPTAN_CONFIG_RESULT` remains the sole precise authority. +- Control, navigation, safety, and simulator error types are derive-ready but + their live owners are not yet attached to a MAVLink worker. +- `KAPTAN_SHUTDOWN` represents only a future completed orderly, + output-inhibited shutdown. It is not a shutdown request, panic, hard-fault, + reset, or retention-record protocol. F722 still uses `panic-halt`; it does + not claim a live panic frame or retained-record replay. + +No diagnostic message may synchronously transmit from a panic handler, hard +fault, ISR, DMA callback, or motor-inhibit path. A later target integration +must inhibit outputs first, persist a validated crash record, then report it +only after the next boot’s static board telemetry is available. diff --git a/docs/src/index.md b/docs/src/index.md index ca152b6..da6abd2 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -14,6 +14,10 @@ Markdown. - New contributors should read [Getting started](getting-started.md). - Board work belongs under [Boards](boards/index.md). - The currently supported closed-loop simulation is [Host SITL](sitl.md). +- [Configuration](configuration.md) distinguishes the current SITL profile + from immutable F722 board policy. +- [Logs](logs.md) and [Errors](errors.md) describe the custom MAVLink + observability surface and its current safety scope. - Before submitting changes, follow [Development and verification](development.md). ## Documentation conventions @@ -22,6 +26,7 @@ Documentation is centralized in `docs/src/`; source directories do not carry README files. Keep pages in Markdown, add each page to `SUMMARY.md`, and place commands beside the assumptions and safety boundary they depend on. -`TODO(configuration)` marks a required configuration contract that has not -been implemented. It is not permission for an operator to substitute runtime -values or bypass an immutable build-time safety decision. +The current configuration contract is intentionally deployment-specific. A +SITL Quad-X profile is a bounded restart-only CBOR snapshot; F722 hardware +selection remains immutable board policy. Neither is permission for an +operator to substitute runtime values or bypass an immutable safety decision. diff --git a/docs/src/logs.md b/docs/src/logs.md new file mode 100644 index 0000000..8d6d2e1 --- /dev/null +++ b/docs/src/logs.md @@ -0,0 +1,61 @@ +# Logs + +Normal host/SITL task code can use the standard facade: + +```rust +log::debug!("estimator waiting for IMU"); +log::info!("configuration loaded"); +log::warn!("range aid stale"); +log::error!("sensor transfer failed"); // emitted as KAPTAN_ERROR +``` + +`kaptan-log` formats once into a fixed bounded buffer, queues locally, and +never sends MAVLink, allocates, blocks, changes flight state, or touches DMA. +The sole MAVLink worker drains admitted records. F722 deliberately does not +link this facade in ISR, DMA, control, actuator, panic, hard-fault, or shutdown +contexts; those paths use static fault mailboxes that the worker turns into +messages later. + +## Receiver contract + +`definitions/kaptan/log.xml` separates ordinary logs from errors: + +```text +KAPTAN_LOG { level, flags, message_length, message[160] } +KAPTAN_ERROR { flags, message_length, message[160] } +KAPTAN_SHUTDOWN { reason } +``` + +A receiver generated from the same `kaptan.xml` revision validates +`message_length <= 160` and decodes exactly that UTF-8 prefix. `KAPTAN_LOG` +displays its text at the MAVLink severity in `level`; `TRACE` is encoded as +`DEBUG` plus the `TRACE` flag. `KAPTAN_ERROR` is error-only and accepts only +`TRUNCATED` and `COALESCED`; a `TRACE` bit is never emitted there. Unknown +future flag bits must be ignored. + +The derived error display text is intentionally not a numeric error catalog; +renaming its Rust module/type/variant changes the display identity. Error +details requiring machine action stay in their owning protocol, notably +`KAPTAN_CONFIG_RESULT`. `KAPTAN_SHUTDOWN` has only its typed reason and is +valid only after an orderly output-inhibited completion. Delivery is bounded +and lossy under link pressure; heartbeat and safety telemetry use separate +paths. + +## Filtering + +The SITL profile’s restart-only `observability.maximum_log_level` accepts +MAVLink severities Error (3) through Debug (7). For example, selecting Warning +permits warning records while suppressing info and debug records. Error-level +records always use `KAPTAN_ERROR` and remain non-filterable. F722 uses its +immutable board log threshold instead, because it has no active runtime +profile. + +Cargo `log/max_level_*` features compile calls away before the facade sees +them; they are not a supported filtering mechanism. The build policy keeps +that decision out of workspace dependencies. + +The tested `SitlConfigRuntime` composition proves `log!` reaches a generated +`KAPTAN_LOG` payload, and rejected configuration replies enqueue a generated +`KAPTAN_ERROR` companion without replacing their authoritative result. `kaptan-sitl +serve` does not yet attach a config/diagnostic MAVLink link, and F722 emits only +outbound telemetry/diagnostic frames while rejecting all inbound authority. diff --git a/docs/src/mavlink.md b/docs/src/mavlink.md index 8487aa8..4c07057 100644 --- a/docs/src/mavlink.md +++ b/docs/src/mavlink.md @@ -18,3 +18,12 @@ Telemetry transmission uses bounded frame classes. A critical frame may replace pending best-effort traffic, but never the DMA-owned active buffer. Completion retries preserve ordering and retain a transiently busy frame for a later service turn. + +The custom Kaptan configuration and log definitions are aggregated by +`definitions/kaptan.xml` from `kaptan/config.xml` and `kaptan/log.xml`. +`KAPTAN_LOG` is an outbound human-readable four-field record. `KAPTAN_ERROR` +is its separate bounded error channel, while `KAPTAN_SHUTDOWN` represents only +a completed orderly output-inhibited shutdown. Configuration messages are GCS +groundwork only: the current F722 receiver rejects every inbound frame before +configuration dispatch. See [Configuration](configuration.md), [Logs](logs.md), +and [Errors](errors.md) for the exact contracts. diff --git a/docs/src/reference.md b/docs/src/reference.md index fe5b1cd..043edff 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -1,19 +1,30 @@ # Reference -## Build-time configuration +This page collects stable limits and points to the detailed contracts. -Board configuration is immutable in the compiled image. Runtime parameter -updates and ground-station tuning are not exposed by the checked-in firmware. +| Surface | Current contract | +| --- | --- | +| Flight profile | One 4 KiB-or-smaller raw CBOR blob, `profile_format = 1`, schema ID `KAPTANPROFILE-01`. | +| SITL file | Private `[generation, raw-profile-blob]` envelope; not a MAVLink upload blob. | +| Config transaction | One owner-bound RAM transaction; typed writes or 192-byte idempotent CBOR chunks; commit is restart-required. | +| Config discovery | Correlated `KAPTAN_CONFIG_INFO_REQUEST` / `KAPTAN_CONFIG_INFO`, then descriptor/value requests. | +| Diagnostics | `KAPTAN_LOG` (51020) for ordinary severity/text, `KAPTAN_ERROR` (51021) for bounded errors, and `KAPTAN_SHUTDOWN` (51022) for completed orderly output-inhibited shutdowns. | +| F722 configuration | Immutable compiled board policy only; inbound MAVLink configuration remains disabled. | -`TODO(configuration)`: a future configuration system must validate and stage -an entire profile while disarmed, commit it atomically, and prove that outputs -remain inhibited throughout staging, activation, and power-loss recovery. +Read [Configuration](configuration.md) for the field/consumer matrix and GCS +upload sequence, [Logs](logs.md) for receiver decoding and filtering, and +[Errors](errors.md) for error propagation and panic scope. -## Simulation package reproducibility +## Verification -The host SITL Docker build uses digest-pinned base images and the locked Rust -dependency graph. The signed Gazebo APT feed is not snapshot-pinned. +Before review, run: -`TODO(reproducibility)`: snapshot/version-pin the Gazebo package set and -verify the repository signing-key fingerprint before treating the simulator -image as byte-for-byte reproducible release input. +```sh +cargo fmt --all --check +cargo test --workspace --locked --offline +cargo clippy --workspace --all-targets --locked -- -D warnings +``` + +The embedded no-std binaries require their target-specific build setup; the +host workspace test suite continues to assert that the telemetry F722 image +has no inbound authority or actuator path. diff --git a/docs/src/sitl.md b/docs/src/sitl.md index e7fe8d9..3e89fb4 100644 --- a/docs/src/sitl.md +++ b/docs/src/sitl.md @@ -32,6 +32,24 @@ never contributes a controller or truth observation. Open , connect to `ws://localhost:9002`, and leave authorization blank to view the world. +## Quad-X profile + +SITL starts through the same central `ConfigManager` composition used by the +host protocol tests. Create and validate a private host profile file with: + +```sh +kaptan-sitl config write-default kaptan-sitl.cbor +kaptan-sitl config validate kaptan-sitl.cbor +kaptan-sitl serve --config kaptan-sitl.cbor +``` + +The file selects the restart-only profile used to build the estimator, +controller, allocator envelope, safety supervisor, and optional log filter at +process start. It is not the raw GCS upload blob. `kaptan-sitl serve` retains +the central manager for that boot but does not yet open a MAVLink config/log +endpoint; see [Configuration](configuration.md) for the exact upload groundwork +and safety boundary. + ## Limits This model does not validate terrain, vision, flow/range sensing, wind,