Diagnostic codes
Every diagnostic the expander can print, by code. Forty-four
today — thirty lang-* and fourteen phys-* — derived straight from
scripts/rigc/’s own construction sites (every error(...)/
warning(...) call in production source, never the golden test
fixtures, whose directory names happen to reuse some of the same
strings). test_diagnostics_reference_drift.py keeps this page and
that source in sync, in both directions: a new call site with no entry
here fails the test suite, and so does an entry naming a code no source
line raises any more.
Each entry names the pipeline stage that raises it (see
Expander API for what each stage does) and what to check
first. The severity in error[code]/warning[code] is fixed per
call site, not per code — a handful of codes below are raised as a
warning at one site; that is called out where it applies.
The two ways a rig can be wrong
The expander’s architecture explains why the pipeline is cut where
it is; the short version a diagnostic code encodes directly: a lang-*
code is something wrong with the rig’s or shield’s files — a dangling
reference, an illegal axis, a shape YAML never declared — caught by the
Loader before a board is ever read. A phys-*
code is something wrong with the hardware the files describe — two
devices at one address, a connector that doesn’t mate, a chip-select pool
with nothing left — caught by the Board reader reader or
the Analyzer once a real board devicetree is in
hand. Neither check can substitute for the other: a lang-* pass never
sees a board, and a phys-* pass never re-derives a fact the loader
already settled.
phys-* — a physical or topological impossibility
Code |
Stage |
Meaning, and what to check |
|---|---|---|
|
Two devices resolve to the same I2C address in one address scope (a bus, or a mux channel), or a free-allocating device’s strap domain is exhausted — every address already claimed. Check the conflicting devices/addresses the message names; fix by moving one behind a mux, using a second bus, or dropping an instance. |
|
|
A carrier’s pass-through bus resolves to more than one candidate bus of the same kind on the named parent socket — ambiguous pass-through is not supported. Check the candidates listed; disambiguate by giving the parent socket only one bus of that kind, or choose a different parent slot. |
|
|
Everything about whether the named board can be read at all: no
board was given (checked by the Front door itself,
before the board reader ever runs — a rig names no board of its
own), the name does not resolve to any devicetree, the devicetree
exists but declares no |
|
|
Two consumers need the same PWM/ADC controller channel — a channel is exclusive, unlike a shared GPIO net. Check the claims listed; use a different socket/channel, or one device. |
|
|
A chip-select pool is exhausted for a scope member, a CS position has no gpio-map entry the board can route, or two exclusive claims resolve to the same SoC pin. Check the CS pool/candidates the message names against what is already claimed. |
|
|
A PWM/ADC function reference targets a socket position that offers
no such channel (no |
|
|
The deterministic |
|
|
A resolved socket’s connector type does not match the shield’s plug type (the connectors do not mate), or more than one instance mates a non-stackable socket. Check the socket’s/plug’s connector type, and whether that type is genuinely stackable. |
|
|
A resolved net (a shared SoC pin or controller channel) has more than one driver, or an exclusively-claimed net is also claimed as a shared signal. Check every claim line the message lists against that one physical net. |
|
|
A rig-pinned strap selection names an address that is not in the strap’s own domain — the copper cannot select it. Check the pinned address against the strap’s declared domain, both printed. |
|
|
A routing jumper’s position was never selected ( |
|
|
Socket resolution failed outright: no board socket (or none
unambiguous) mates the shield’s plug type, an explicitly-named
|
|
|
A shield’s devices need a bus the resolved socket does not expose
— subset exposure is declared by absence — or, for a carrier, a
pass-through/PWM/ADC-map row’s declared cell count or routed
position does not match what the named parent socket actually
offers. Check the socket’s declared |
|
|
A |