feat(firmware): validate configuration and migrate sensor-driven flight APIs

Validate configuration through its owning schemas and keep board
declarations separate from shared F722 resource ownership. Bound USB
transitions, isolate transport failures and retain restart-only activation.

Migrate navigation and flight consumers with the sensor and schema
contracts. Require explicit installation data and synchronous output
authority; board motor outputs remain inhibited.

Validation: assembled-prefix host tests, strict Clippy, platform/USB tests
and both ARM release builds. Final-source coverage and scoped Miri/Kani
evidence are retained separately from hardware qualification.
This commit is contained in:
Onur Özkan committed 2026-11-07 18:12:11 +03:00
1 parent fb1b8af2d1
commit f9a61a086f
211 files changed
+45657 -12740

No files matched your search

+57 -20
View File
@@ -1,11 +1,13 @@
//! Non-blocking, chip-select-scoped SPI transfer contract.
//!
//! A selected device owns electrical chip-select behavior. A driver retains its
//! transfer storage until a terminal completion event; implementations submit
//! DMA or interrupt-driven work and never wait for a peripheral flag.
//! A selected device owns electrical chip-select behavior and asynchronous
//! transfer storage. Submission copies in; successful completion copies out.
//! No caller borrow or caller address may survive either method call.
#![no_std]
pub mod dma;
/// Terminal outcome reported by a selected SPI device.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SpiCompletion {
@@ -17,28 +19,63 @@ pub enum SpiCompletion {
TransferFault,
}
/// Failure to accept and copy out a completed transfer. No receive bytes are
/// changed on error.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CompletionError {
/// No terminal event: leave the active transfer entirely untouched.
NotPending,
/// There is no submitted transfer to complete.
NotActive,
/// The destination length differs from the submitted length.
InvalidLength,
/// The transfer failed; no receive bytes are usable.
TransferFault,
/// Quiescence could not be proven. Storage and route are permanently held.
Quarantined,
}
/// Owns one chip-select-scoped, non-blocking SPI route.
///
/// `start_transfer` begins a complete transfer and returns without waiting for
/// a peripheral status flag. The caller owns both buffers until the board
/// reports a terminal `SpiCompletion`; `complete_transfer` releases the route
/// after that terminal outcome.
/// Moving, dropping, or forgetting the device or caller buffers during a
/// transfer must be memory-safe. Hardware accesses only implementation-owned
/// storage whose allocation outlives hardware activity, including cancellation.
pub trait SpiDevice {
/// Failure to submit a transfer.
type StartError;
/// Starts one complete full-duplex transfer.
///
/// Implementations assert chip select before submitting and deassert it on
/// every terminal completion or submission failure. `receive` receives one
/// octet for each `transmit` octet; the two ranges must have equal length.
fn start_transfer(
&mut self,
transmit: &[u8],
receive: &mut [u8],
) -> Result<(), Self::StartError>;
/// Identifies a temporary admission rejection. No transfer was accepted.
/// Drivers may retry the same pending operation within their deadline.
fn is_busy(_error: &Self::StartError) -> bool {
false
}
/// Releases transport ownership after a hardware ISR acknowledged a
/// terminal completion. This must not poll or wait.
fn complete_transfer(&mut self, completion: SpiCompletion);
/// Copies `transmit` into bounded route-owned storage and starts one
/// full-duplex transfer. Empty/oversized submissions must fail safely.
///
/// No pointer into `transmit` is retained. Chip select is asserted before
/// submission; rejecting a concurrent submission must not disturb it.
fn start_transfer(&mut self, transmit: &[u8]) -> Result<(), Self::StartError>;
/// On `Complete`, proves hardware quiescence before copying exactly the
/// submitted number of bytes to an equally sized `receive` and releasing
/// chip select. An interrupt notification alone is not proof of quiescence.
///
/// `NotPending` returns that error without aborting or changing anything.
/// Faults cancel the transfer without copying out. Any bounded hardware
/// shutdown that cannot prove quiescence must quarantine the route and its
/// storage permanently, preventing reuse. No destination pointer is retained.
/// Passing `TransferFault` also requests cancellation without an IRQ. It must
/// perform the same bounded shutdown and return `TransferFault` only after
/// quiescence, or `Quarantined` if that cannot be proved. No bytes are copied.
///
/// Providers must validate current hardware progress, not trust a notification
/// from a previous transfer. Before reuse, drain old hardware flags/data. A
/// delayed notification may fault a new incomplete transfer but must never
/// publish old receive storage as a new result.
fn complete_transfer(
&mut self,
completion: SpiCompletion,
receive: &mut [u8],
) -> Result<(), CompletionError>;
}