Transport: local UART0 at 115200 baud, 8N1. The host HAL substitutes a bounded ASCII test channel around the same binary codec/kernel. All multi-byte fields are little-endian. A frame is exactly 64 bytes. The CRC detects corruption; it does not authenticate a sender. This protocol has no actuator values, arming command, flight position or velocity command.
| Offset | Bytes | Field |
|---|---|---|
| 0 | 2 | Magic DR (0x44, 0x52) |
| 2 | 1 | Major protocol version, exactly 1 |
| 3 | 1 | Kind: hello=1, diagnostic lease=2, stop=3, status=4 |
| 4 | 4 | Nonzero uint32 sequence, monotonic within each direction/session |
| 8 | 8 | uint64 board boot token; hello request uses zero |
| 16 | 8 | uint64 host session token, fresh and nonzero per hello |
| 24 | 8 | uint64 synthetic sample capture time in board microseconds; commands echo a fresh sample |
| 32 | 4 | uint32 lease duration/remaining microseconds |
| 36 | 4 | int32 synthetic scalar, arbitrary test units |
| 40 | 4 | uint32 successful sample/tick counter |
| 44 | 4 | uint32 deadline failure counter |
| 48 | 4 | uint32 capability/state flags |
| 52 | 4 | uint32 maximum accounted tick execution time in microseconds |
| 56 | 4 | uint32 kernel state bytes |
| 60 | 4 | CRC32/ISO-HDLC of bytes 0..59, reflected polynomial 0xEDB88320, initial/final XOR 0xFFFFFFFF |
Independent Python struct/zlib fixtures live in tests/fixtures/runtime/frames.json. Both codecs
are tested against external CRC/field values. C++ decodes fields without unaligned struct casts.
Signed sample conversion is explicit, and TypeScript uses bigint for all uint64 fields.
Flags: bit 0 synthetic sensor, bit 1 neutral-only output, bit 2 diagnostic lease active, bit 3 latched deadline fault, bit 4 latched clock fault, bit 5 watchdog-caused reset, bit 6 sample valid. All other bits are unsupported. Kernel state is <=128 bytes, lease duration is <=100000 us, and reported execution must be <=500 us for the Pi session to consider the board healthy. A watchdog reset flag is diagnostic; it does not restore a previous session or grant authority.
The scalar is (successful_tick_count % 2001) - 1000, with the timestamp of that tick's start.
It is deliberately not acceleration, attitude or position. Status carries the latest sample;
sequence changes alone cannot refresh its age on the Pi. Status normally emits at 10 Hz and in
response to commands. Reply buffering can delay transmission; the Pi's progressing-sample check
and board-clock echo limit constrain diagnostic leases rather than comparing unrelated clocks.
- The Pi creates a random nonzero 64-bit session token and sends hello with sequence 1. Boot token, timestamp, lease duration and all diagnostic/status-only fields must be zero.
- The board immediately clears any existing diagnostic lease and binds the host token. Status echoes it alongside the random per-boot token, exact version and capability flags. Boot tokens are generated by the Pico SDK random API on the board. The host test HAL uses a fresh supervisor-owned launch nonce, checked on every host status response.
- The Pi verifies the echoed token, nonzero boot token, known capabilities, valid sample, health, state-size bound and monotonic status sequence. Invalid status loses the session.
- Lease/stop commands must match both tokens and have a strictly larger command sequence. Their echoed sample time must be at or after the session start, no later than the board clock, and at most 50000 us old when processed. The board grants a lease for 1..100000 us from its own receipt time. The Pi also refuses to generate a lease once sample progress is >50 ms old locally.
- An unrefreshed lease expires at its boundary. Stop sets it to zero. Either way the output stays neutral. Invalid identity, version, CRC, fields, sequence or freshness clears the session/lease. Deadline/clock faults additionally latch until reset and stop hardware watchdog feeding.
No dynamic allocation is used by the native kernel/protocol. Pico RX and TX buffers are each
64 bytes; byte processing is capped per tick and transmission never blocks waiting for a peer.
Noise/header mismatch revokes authority and resynchronizes on DR. An incomplete frame cannot
extend a lease. Sequence exhaustion needs a new handshake; counters do not silently wrap authority.
The board uses its monotonic microsecond timer for capture, lease expiry and command freshness. The Pi uses one local monotonic clock to age sample progress. It echoes board timestamps unchanged; it never treats them as Pi time. Sample timestamps and tick counts must not regress within a session. Recorded captures are diagnostic evidence and never accepted as live authority.
Tokens and CRC are replay/corruption separation on a trusted local bench wire, not encryption,
signatures or secure boot. A malicious physical sender can disrupt a bench session. Authenticated
transport and flight authority belong to later roadmap issues. createRuntimeSession is a bench
capability link, not a FlightAdapter, and cannot cause non-neutral output.
Start the host with drone_runtime_host --stdio --boot-id <16 lowercase hex characters>.
The supervisor allocates a fresh nonzero 64-bit cryptographic random nonce for each launch;
missing, zero, malformed or additional arguments fail before processing input. This startup
argument binds the host process to its supervisor and does not attest its executable or hardware.
Older supervisors and host binaries must be rebuilt together. The 64-byte wire format stays v1.
The host accepts only tick <uint64 microseconds> and frame <128 lowercase hex characters>, each newline-terminated and bounded by a 160-byte input buffer. Each returns one
128-character status-frame hex line. tick advances virtual time; it does not sleep in real time.
This channel is not a firmware transport or public network service. The Stacks harness serializes
requests, bounds response lines and times out unresponsive processes. Every returned status must
match the supervisor's launch nonce. Invalid responses kill the process and permanently fail
that transport. Returned status frames are immutable. Closing waits for actual process exit and
returns its exit code and signal; repeated closes retain the same result.
Successful close also requires stdout completion without extra bytes and empty
stderr. The one-second close deadline rejects inherited pipes that remain open
after parent exit, cancels readers and retains cleanup failures. These checks
support the owned host slot trial.
Host stdin uses an owned nonblocking POSIX pipe. The supervisor creates it with
mkfifo, opens and verifies its descriptors, then unlinks its private directory
before launching the process. Writes handle partial progress and EAGAIN within the
existing two-second response deadline. Closing the writer drops the owned descriptor
without waiting for a buffered flush. The deadline also cancels an inherited output
read; killing an already-exited parent alone cannot finish that read.
The optional DS sensor stream shares UART TX as complete 128-byte frames. DR remains 64 bytes. Awaited DR replies take priority when the current frame finishes; partial frames are never overwritten. UART state has a 64-byte RX buffer and a 128-byte TX buffer.