Skip to main content
The rig TOML is the single source of truth for hardware configuration. It maps logical names to real hardware, specifies backends, and controls timeouts. Test code never contains hardware details — they all live here.

Full example

[rig]
name         = "bench_01"
platform     = "orin_nx"
spec_version = "1.0"
backend      = "hardware"

[rig.can.powertrain]
interface = "can0"
bitrate   = 500000
fd        = false
backend   = "socketcan"

[rig.can.chassis]
interface = "can1"
bitrate   = 250000
fd        = false
backend   = "peak"

[rig.ethernet.chassis_eth]
interface      = "eth1"
ip             = "169.254.0.1"
someip_backend = "python-someip"
doip_backend   = "python-doip"

[rig.power.ecu_main]
backend = "virtual_power"
default = "off"

[rig.gpio]
ignition_enable = { pin = 22, direction = "out", default = false, backend = "virtual_gpio" }
fault_indicator = { pin = 27, direction = "in",  backend = "virtual_gpio" }
reset_line      = { pin = 24, direction = "out", default = false, backend = "virtual_gpio" }

[rig.ecus.engine_ecu]
name            = "Engine_ECU"
logical_address = 0x0001
transport       = "doip"
doip_interface  = "chassis_eth"
power_rail      = "ecu_main"
boot_timeout    = 8.0

[rig.definitions]
can_dbc = "defs/powertrain.dbc"
eth_dbc = "defs/chassis.dbc"

[rig.cloud]
url                = "https://your-server.example.com"
registration_token = "REGISTRATION_TOKEN_HERE"

[rig] — root section

name
string
required
Rig identifier. Used in the cloud dashboard, agent hello message, and as the TOML filename convention. Letters, numbers, hyphens (e.g. bench_01, orin-bench-prod).
platform
string
required
Hardware platform name. Informational only — used in dashboard display. Examples: orin_nx, s32g, rcar_s4, virtual, custom.
spec_version
string
required
TOML schema version. Always "1.0" for current releases.
backend
string
required
Top-level backend hint. "virtual" enables virtual backends for all interfaces. "hardware" requires each interface to specify its own backend.

[rig.can.<name>] — CAN interfaces

Each [rig.can.<name>] section defines one CAN interface. The <name> key (e.g. powertrain, chassis) is used in rig.can routing — it is never referenced from test code.
interface
string
required
OS interface name (e.g. can0, can1, PCAN_USBBUS1).
bitrate
integer
required
Nominal bitrate in bits/second. Common values: 125000, 250000, 500000, 1000000.
fd
boolean
default:"false"
Enable CAN-FD mode. Set to true for CAN-FD buses. Requires an FD-capable adapter and backend.
backend
string
required
Backend driver. Options: virtual, socketcan, peak. See Backends.

Multiple CAN interfaces

You can define as many CAN interfaces as your rig has:
[rig.can.powertrain]
interface = "can0"
bitrate   = 500000
backend   = "socketcan"

[rig.can.chassis]
interface = "can1"
bitrate   = 250000
backend   = "socketcan"

[rig.can.diagnostic]
interface = "can2"
bitrate   = 500000
backend   = "socketcan"

[rig.ethernet.<name>] — Ethernet interfaces

Used for DoIP and SOME/IP communication.
interface
string
required
OS interface name (e.g. eth0, eth1).
ip
string
required
Local IP address to bind to. For DoIP targets on a dedicated link: 169.254.0.1 (link-local).
someip_backend
string
required
SOME/IP backend. Options: python-someip, virtual. See Backends.
doip_backend
string
required
DoIP backend. Options: python-doip, virtual. See Backends.

[rig.power.<name>] — Power rails

backend
string
required
Power backend. Options: virtual_power, gpio_relay, bench_psu. See Backends.
default
string
default:"\"off\""
Initial power state when the rig connects. "on" or "off".
gpio_pin
integer
GPIO pin number for gpio_relay backend.
port
string
Serial port for bench_psu backend (e.g. /dev/ttyUSB0).
model
string
Instrument model for bench_psu backend (e.g. keysight_e3631a).

[rig.gpio] — GPIO pins

GPIO pins are declared as inline tables under [rig.gpio]:
[rig.gpio]
ignition_enable = { pin = 22, direction = "out", default = false, backend = "virtual_gpio" }
fault_indicator = { pin = 27, direction = "in",  backend = "virtual_gpio" }
reset_line      = { pin = 24, direction = "out", default = false, backend = "virtual_gpio" }
Each pin entry accepts:
pin
integer
required
GPIO pin number (BCM numbering on Raspberry Pi; board-specific elsewhere).
direction
string
required
"in" or "out".
default
boolean
default:"false"
Initial state for output pins. Ignored for input pins.
backend
string
default:"\"virtual_gpio\""
GPIO backend. Options: virtual_gpio, rpi_gpio. See Backends.

[rig.ecus.<name>] — ECU definitions

Each ECU has a logical address and a transport. The framework uses this to route UDS commands and manage power lifecycle.
name
string
required
Human-readable ECU name (e.g. Engine_ECU, Orin_NX). Shown in dashboard and reports.
logical_address
integer
required
UDS logical address (hex notation allowed: 0x0001).
transport
string
required
Transport for UDS. "doip" or "can_isotp".
doip_interface
string
Key of the [rig.ethernet.<name>] interface to use for DoIP. Required when transport = "doip".
can_interface
string
Key of the [rig.can.<name>] interface to use for ISO-TP. Required when transport = "can_isotp".
power_rail
string
Key of a [rig.power.<name>] rail. If set, rig.ecu.power_on() and rig.ecu.power_off() control this rail.
boot_timeout
float
default:"5.0"
Seconds to wait for the ECU to become responsive after power-on. Platform-specific values belong here — never in test code (Rule R6). Example: virtual ECU 0.1, Nvidia Orin 8.0.

[rig.definitions] — DBC files

can_dbc
string
Path to the CAN DBC file. Relative to the directory containing the TOML file.
eth_dbc
string
Path to the Ethernet (SOME/IP) DBC/descriptor file.
The key names can_dbc and eth_dbc are also used by crucihil analyze to infer the interface type of each signal corpus. Use these exact key names.

[rig.cloud] — Cloud connection (optional)

url
string
HTTP(S) base URL of the CruciHiL control plane.
registration_token
string
One-time token used for agent self-registration on first boot. The agent exchanges this for a permanent API key and stores it in ~/.crucihil/credentials.toml. Once registered, this field is no longer needed.

Virtual rig (no hardware)

The virtual rig uses in-process simulated backends for all interfaces. Use it for CI and local development.
[rig]
name         = "Virtual_Sim"
platform     = "virtual"
spec_version = "1.0"
backend      = "virtual"

[rig.can.can0]
interface = "can0"
bitrate   = 500000
fd        = false
backend   = "virtual"

[rig.ethernet.eth0]
interface      = "eth0"
ip             = "127.0.0.1"
someip_backend = "python-someip"
doip_backend   = "virtual"

[rig.power.ecu_main]
backend = "virtual_power"
default = "on"

[rig.gpio]
ignition_enable = { pin = 22, direction = "out", default = false, backend = "virtual_gpio" }

[rig.ecus.ecu_main]
name            = "Virtual_ECU"
logical_address = 0x0001
transport       = "doip"
doip_interface  = "eth0"
power_rail      = "ecu_main"
boot_timeout    = 0.1

[rig.definitions]
can_dbc = "defs/vehicle_can.dbc"

Configuration validation

CruciHiL validates the TOML with Pydantic at rig initialization — before any test runs. Schema errors produce a ConfigurationError that marks the run as BLOCKED (not FAIL). This means a config typo never appears as a firmware regression. You can validate a TOML without running any tests:
python -c "from crucihil.hal.rig import Rig; Rig.from_toml('rigs/bench.toml')"
No error means the config is valid.

See also