Configure a product and make I/O progress¶
Start with the external application tutorial. Use the same fixed SDK or checkout for the commands below. Commands run from its source root; product TOML, tasks, buffers and recovery policy stay in the product repository. The resolver reports supported software choices, not electrical verification of a connected board.
Choose and compare a complete configuration¶
Inspect choices before authoring a complete assembly. This query requires no guessed backend or clock:
python tools/configure/configure.py list-bindings \
--board stm32f407_qiming_v31 --kind uart
python tools/configure/configure.py init \
--board stm32f407_qiming_v31 --backend baremetal --clock hse8-pll168 \
--profile uart --binding uart1 --instance link0 \
--output /tmp/product-uart.toml
python tools/configure/configure.py explain --assembly /tmp/product-uart.toml
init refuses an existing file. Profiles empty, gpio and uart write visible
TOML values and run the normal resolver; nonempty profiles require an explicit
binding. A rejected route is not replaced with another one. Read the generated
TOML before adopting its baud rate, event capacity, IRQ priority and budgets.
For an external Board, both init and list-bindings accept --board-package
instead of --board. The command resolves that package path from the working
directory; init writes it relative to the new TOML directory. Moving the whole
product tree preserves this relationship. The reviewed Board package remains
separate from the product assembly; use the Board porting guide
for package contents and provider boundaries.
The explanation lists public faces, modes, clock, resources, memory domains,
declared budgets and execution duties. list-bindings --json includes
mode_contracts, resource claims, fact_sources and limitations. A binding is
still configuration-required: backend, clock and all selected instances must
resolve together. Missing physical PCB facts remain unknown. MCU queries state
not_established_by_configuration; Native states not_applicable.
Each candidate mode lists its own resource_keys, occupied_resources and
resource_scope. A polling mode does not claim the alternative DMA route.
Board-first queries retain known SoC and Board reservations without inventing an
OS owner before a backend is selected. Assembly queries read facts matching the
resolved input hashes. Options can add requirements, so this projection does not
replace full-assembly admission. Use the exact support query
to separate configuration acceptance from model, ARM, SDK and physical evidence.
After editing a separate next assembly, compare effective changes:
python tools/configure/configure.py diff \
--assembly /tmp/product-uart.toml --against /tmp/product-uart-next.toml
python tools/configure/configure.py explain \
--assembly /tmp/product-uart-next.toml --json
Both assemblies must resolve. The diff reports effective platform, route, mode,
endpoint, storage and budget changes; renaming a source file alone is not a
behavior change. JSON distinguishes absent fields from explicit null. Scripts
that previously consumed default JSON from explain must now pass --json.
Editor hints are assistance; the resolver remains the acceptance authority.
The diff also groups impacts into factory_ids, public_interface,
transfer_contract, execution and storage. Each item identifies its effective
path, before/after value and review obligation. Changed or reordered factory IDs
may require consumer changes; a new executor or DMA mode needs its lifecycle and
storage
contract reviewed. These are declared configuration impacts, not measured timing,
memory savings or an assertion that a consumer was migrated.
A conflict diagnostic identifies the authored file/key and competing resource owners. Correct those inputs, then configure again. Never fix generated C, weaken a DMA reservation or change a clock implicitly to make a build pass. Configuration budgets are declarations; measure the actual linked image before claiming resource savings. See the assembly reference and support matrix.
Automation can add --diagnostics-json to receive one structured rejection on
standard error, with exit code 1; successful standard output keeps its existing
format. Human and JSON diagnostics use the same error record. Unknown/missing
fields preserve their context and key sets; resource conflicts identify the
resource and competing claims, including owner, mode and source. These records
locate authored inputs without silently correcting them.
CLI argument syntax errors retain argparse diagnostics and exit code 2.
Preview the maintained software plan¶
The plan/artifact commands, Settings, wait selection and serial extensions in
this iteration require a development checkout containing those changes. They do
not modify the published v0.2.1 archive; installed-SDK support follows actual
verification of the corresponding new SDK.
From the fixed development checkout, inspect the existing complete software plan before starting expensive validation:
python tools/dev/dev.py plan \
--output-root /tmp/nexus-planned-run-001 \
--json /tmp/nexus-plan-001.json
Choose a new JSON path in an existing parent directory; the future run directory
is not created. The preview derives ordered commands, deadlines, selection
reasons, checker and preset metadata, and input identities from the maintained
plan. It does not execute a process, install tools, use equipment or access the
network. With no observation, case counts remain unknown and the operation
needs no prior test run. --preset filtering is rejected; the complete authored
plan remains the selection authority.
To include previously observed cases, first build the selected Native preset, then explicitly collect case-list evidence with the existing Native producer:
python scripts/ci/native_contracts.py --preset native-debug --observe-only
python tools/dev/dev.py plan \
--output-root /tmp/nexus-planned-run-002 \
--observation native-debug=build/native-debug/tdd/io-property-inputs.json \
--json /tmp/nexus-observed-plan-002.json
--observe-only executes each manifest binary’s unfiltered case-list process;
it does not execute test cases or CTest, and writes no execution-success summary.
Prior summaries and snapshots retain unique before-observe paths. The normal
producer still executes the complete CTest and Google plan, including disabled
cases. The same snapshot binds all manifest binaries, their object contexts and
a deduplicated conservative superset of current materialized compiler inputs,
shared dependencies and linked files. Ninja supplies the metadata through
original command receipts; preview itself never launches Ninja. These facts
bind current bytes, without proving a fresh compilation or inventing another
build graph. See the development tool contract for
bounds and exact receipt requirements.
Preview accepts an explicit observation only while its source, objects, headers,
archives, binaries, metadata and successful original discovery receipts still
match. Receipts must belong to this build and follow its snapshot. Stale,
failed, changed or incomplete observations reject; a relocated checkout or SDK
needs a new observation. Parameterized and disabled identities are preserved.
Cases present in the reviewed lifecycle catalogue show its invariant and
limitations; unreviewed cases remain unknown, without a coverage percentage.
The displayed result means “previously observed and current inputs match”; it
never means these cases executed during preview or passed.
Known host stages need no equipment. A HIL preparation stage can show declared
fixture tests and pending measurements, but missing resolved configuration stays
configuration_pending; routes and station facts are not guessed. Unknown
hardware needs stay unknown, and physical status stays not_executed.
Every preview stage remains not_executed and qualification remains false.
Remove only your own preview JSON when no longer needed.
After a successful build, inspect its captured outputs without guessing which
ELF belongs to the selected configuration. Replace the path below with that
build’s actual quality/build-provenance.json:
python tools/dev/dev.py artifacts \
--provenance build/my-board/quality/build-provenance.json \
--json /tmp/nexus-artifacts-001.json
The command verifies the provenance and resolved identity before listing source, configuration, artifact roles and the original command receipt. Missing, changed, stale or mismatched inputs reject rather than becoming a successful artifact view. The optional JSON path must be new. Inspection neither builds nor accesses equipment, and does not grant the current checkout, software or hardware a new qualification.
Use optional Settings and networking mechanisms¶
Select settings in the assembly’s component list to link Nexus::Settings.
The caller first opens Storage, then supplies Settings metadata, a disjoint
staging buffer, entry capacity and a product-defined schema. Integer keys and
copied byte values stay bounded. Get/set/remove operate on staging; only explicit
commit writes Storage, and close discards uncommitted changes. Unknown schemas
or corrupt loads are errors, not empty writable stores. After a mutating commit
failure, reopen Storage and Settings to observe the surviving commit before
retrying. Defaults, migration, authorization and Flash regions remain product
policy. Read settings.h and the
component contract for detailed ownership.
The optional Nexus::LwIP target admits the organization-hosted X-Gen-Lab/lwip
2.2.1 gitlink 77dcd25a and its fixed source closure. It is excluded from the
default build until explicitly selected. It uses NO_SYS=1: a product loop or
task advances one serialized owner, without an implicit RTOS stack port. It
reuses Ethernet frame loans and bounded memory. The reviewed slice covers static
IPv4/ARP/ICMP/UDP and limited TCP integration; complete TCP connection lifecycles,
DHCP, DNS, IPv6, VLAN, TLS and MQTT remain separate exits. Read the
network integration contract for source,
SDK, clock, memory and stop prerequisites. Source admission and development SDK
consumption do not establish a software candidate, full network-platform,
ARM or physical acceptance.
Assign one executor and retain borrowed storage¶
The factory returns an existing typed face. Platform start, request admission, progress, completion, recovery and shutdown remain separate operations. Choose one execution recipe explicitly:
Recipe |
Progress owner |
Storage and shutdown responsibility |
|---|---|---|
Main loop |
The loop calls the selected service steps; fixed IRQ entries perform bounded IRQ work |
Keep request and buffers alive through settlement; stop admission, cancel or drain, observe settlement, join observers, then stop |
Exclusive task |
One product task owns direct operations; declared IRQ policy permits only its selected OS interaction |
Wake and service explicitly; a task timeout does not revoke a borrowed buffer or permit task-stack destruction |
Shared bus owner |
Callers submit bounded slots; one owner services the controller and endpoints |
Queue capacity, callbacks and storage are explicit; stop admission, drain accepted slots and controller references, join observers, then destroy the owner |
These are application choices, not three hidden driver workers. Product examples
live in nexus-examples:
templates/{native,qiming,sky,liangshan}, apps/shared_spi_runtime and
apps/stream_recovery.
Use their README with the fixed examples revision associated with your platform.
The SPI Native example and FreeRTOS POSIX-host exercise are separate scopes;
Native Platform does not accept backend = "freertos". A software two-CS fixture
does not establish a second physical CS on a launch board.
For finite requests, REJECTED retains no caller references. ACCEPTED borrows request and transfer storage until acquire-observed SETTLED. Cancel and deadline expiry request progress toward withdrawal; they do not settle the request. QUARANTINED preserves storage and cleanup obligations. SETTLED does not imply a successful transfer or that callbacks and observers have already joined. Read ownership before placing asynchronous storage on a stack or stopping a worker.
For several authoritative predicates sharing one wait port, nx_wait_select
checks a caller-owned source array from an explicit cyclic start index. It
returns an observed-ready index without acquiring or consuming that source.
The caller chooses fairness by advancing the next start index, wires every
publisher to the same port, and owns service/timer progress. Stop and join
publishers and waiters before reclaiming their state. There is no implicit
subscription, dispatch, worker or resource transfer; the public wait contract
still governs arm/recheck and the absolute deadline.
For streams, a consumer releases each acquired block explicitly. Slow consumers can cause loss or stop on backpressure according to the selected mode; providers must not overwrite outstanding loans. Stop may return BUSY until loans and hardware references drain. Restart uses a new valid lifecycle after complete stop; clearing counters is not recovery. The H743 continuous-mode exercise is a separate exact ARM configuration, not a claim that the three launch boards have identical continuous-mode wiring.
Diagnose facts without changing ownership¶
nx_io_diagnose in nexus/io/diagnostic.h composes copied request and stream
observations with explicitly known lifecycle, owner, service-time and observer
facts. It neither reads live MMIO nor invokes service or recovery. Its independent
finding bits can coexist; unknown_facts preserves missing information. No
findings does not certify health.
A request that stops advancing does not prove the service loop was omitted.
SERVICE_OVERDUE requires finite timestamps in the same monotonic domain and a
positive declared maximum gap; reversed time rejects with STATE. Owner admission
fields are known only after a successful owner diagnostic snapshot. BUSY alone
does not prove a full queue. Outstanding stream blocks can be producer, ready or
consumer loans; the ordinary cursor says nothing about a private preposted slot.
Application escalation still owns retry, safe outputs and reset policy.
nx_dma_storage_validate checks the complete explicit reservation separately
from its payload. For example, a 17-byte payload may use a caller-owned 64-byte
reservation aligned to 32-byte cache lines. The entire reservation must already
fit its declared DMA-visible domain and whole-line ownership. The helper does
not round, allocate, bounce, perform cache maintenance or replace provider mode
admission. Deadline expiry never permits reusing the reservation before drain.
The optional owner observation adds accepting, queued and slot_available.
Recompile consumers because its public observation/sidecar layout changed.
Default owner and provider structures do not gain these fields. Measure optional
sidecar storage for the selected ABI; it is not assumed to be free.
Plan daily device operations separately from qualification¶
For flash/debug, use an identified equipment file and provenance from the actual successful build. Monitor may run without build association:
python tools/dev/dev.py flash --target /path/equipment.json \
--provenance /path/build-provenance.json --elf /path/application.elf
python tools/dev/dev.py debug --target /path/equipment.json \
--provenance /path/build-provenance.json --elf /path/application.elf
python tools/dev/dev.py monitor --target /path/equipment.json \
--provenance /path/build-provenance.json
The default prints a plan. Actual execution requires --execute --output with a
new owned directory. Flash/debug require matching board/part, image, probe serial
and pinned tool/configuration bytes; they do not require a serial console.
Monitor requires the board, stable serial by-id and station lock, but may omit
build provenance: that result states image_linkage = unassociated, not an
image-qualified observation. Monitor uses the explicitly selected host-supported
standard baud rate with 8N1 and finite duration; 115200 remains the default.
Unknown rates or a TTY configuration mismatch fail rather than selecting a
different speed. Host acceptance does not prove the physical device baud rate.
EOF or disconnection fails. Debug binds loopback. Failed or cancelled device
operations retain their locks for explicit inspection; normal completion releases
them. A successful daily operation does not qualify HIL. Until real equipment is
connected, record physical execution as not_executed. The
performance and HIL guide owns capture and qualification.
For one bounded Linux batch, add --client to debug. This uses the official
GDB/OpenOCD pipe transport and rejects --port; the default debug server keeps
its loopback TCP workflow. The target JSON must explicitly identify the GDB
executable in gdb_client.tool with path, size and sha256. Optional
gdb_client.commands uses the same file identity fields and replaces the default
info threads command. Review that file as executable operator input. GDB starts
with automatic scripts disabled, loads the exact provenance-bound ELF, attaches,
runs the selected commands and detaches. Tool/configuration/ELF identities are
checked before and after execution. The finite timeout covers the owned process
chain; failure or cancellation withdraws it and retains station quarantine.
No executable or target is auto-discovered. See the
development tool contract for the equipment schema
and command example. Host pipe fixtures do not establish physical probe support.
Development monitor remains Linux/POSIX. The session-bound terminal phases are
acquiring, owned, releasing and released. After confirmed helper
withdrawal, the parent may restore its originally held descriptor only when
owned proves this session’s exclusive ownership. An already released helper
does not authorize another restore or exclusive-release operation: another
process may now own the terminal. Unknown, corrupt or intermediate phases,
unconfirmed withdrawal and identity failures retain quarantine without touching
another owner’s terminal. The parent never opens a replacement by-id device.
Primary I/O failure and cleanup failure remain separately visible, including their exception cause/context chains; a cleanup exception must not hide an earlier EOF or read failure. Independent cleanup errors remain in the operation record. External SIGKILL of the parent cannot guarantee restoration. The baud-rate extension does not expand formal HIL console admission or establish Windows/macOS support. See the serial ownership regressions and rate/cancellation regressions.